home *** CD-ROM | disk | FTP | other *** search
/ ADA Programming Guide / ADA Programming Guide.iso / ada_gnu / adainc / a-teioau.adb < prev    next >
Text File  |  1996-01-30  |  81KB  |  3,228 lines

  1. ------------------------------------------------------------------------------
  2. --                                                                          --
  3. --                         GNAT RUNTIME COMPONENTS                          --
  4. --                                                                          --
  5. --                      A D A . T E X T _ I O . A U X                       --
  6. --                                                                          --
  7. --                                 B o d y                                  --
  8. --                                                                          --
  9. --                            $Revision: 1.34 $                             --
  10. --                                                                          --
  11. --           Copyright (c) 1992,1993,1994 NYU, All Rights Reserved          --
  12. --                                                                          --
  13. -- The GNAT library is free software; you can redistribute it and/or modify --
  14. -- it under terms of the GNU Library General Public License as published by --
  15. -- the Free Software  Foundation; either version 2, or (at your option) any --
  16. -- later version.  The GNAT library is distributed in the hope that it will --
  17. -- be useful, but WITHOUT ANY WARRANTY;  without even  the implied warranty --
  18. -- of MERCHANTABILITY  or  FITNESS FOR  A PARTICULAR PURPOSE.  See the  GNU --
  19. -- Library  General  Public  License for  more  details.  You  should  have --
  20. -- received  a copy of the GNU  Library  General Public License  along with --
  21. -- the GNAT library;  see the file  COPYING.LIB.  If not, write to the Free --
  22. -- Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.        --
  23. --                                                                          --
  24. ------------------------------------------------------------------------------
  25.  
  26. with Ada.Finalization; use Ada.Finalization;
  27. with System;           use System;
  28. with System.Img_BIU;   use System.Img_BIU;
  29. with System.Img_Int;   use System.Img_Int;
  30. with System.Img_LLB;   use System.Img_LLB;
  31. with System.Img_LLI;   use System.Img_LLI;
  32. with System.Img_LLU;   use System.Img_LLU;
  33. with System.Img_LLW;   use System.Img_LLW;
  34. with System.Img_Real;  use System.Img_Real;
  35. with System.Img_Uns;   use System.Img_Uns;
  36. with System.Img_WIU;   use System.Img_WIU;
  37. with System.Val_Int;   use System.Val_Int;
  38. with System.Val_LLI;   use System.Val_LLI;
  39. with System.Val_LLU;   use System.Val_LLU;
  40. with System.Val_Real;  use System.Val_Real;
  41. with System.Val_Uns;   use System.Val_Uns;
  42.  
  43. package body Ada.Text_IO.Aux is
  44.  
  45.    ----------------
  46.    -- Local Data --
  47.    ----------------
  48.  
  49.    Max_Num_Of_Files : constant := 60;
  50.  
  51.    Line_Feed : constant Character := Ascii.Lf;  --  Character'Val (16#0A#);
  52.    Nul       : constant Character := Ascii.Nul; --  Character'Val (16#00#);
  53.    Page_Mark : constant Character := Ascii.Ff;  --  Character'Val (16#0C#);
  54.  
  55.    --  The term "file" here is used in the same way as in the Ada Reference
  56.    --  Manual, that is it refers to an object of some "file_type". Otherwise
  57.    --  "external file" is used.
  58.  
  59.    Open_Files : array (1 .. Max_Num_Of_Files) of File_Type;
  60.    --  Used to make sure we don't open too many files and that we do not
  61.    --  open the same file twice.
  62.  
  63.    Scanning_From_File : Boolean;
  64.    --  Determines if characters are read from a File (True) or String (False).
  65.  
  66.    type Temp_File_Rec;
  67.    type Link is access Temp_File_Rec;
  68.  
  69.    type Temp_File_Rec is record
  70.       File_Name : Pstring;
  71.       Next      : Link;
  72.    end record;
  73.  
  74.    Temp_Files : Link;
  75.  
  76.    type Work_String_Type is array (0 .. 1023) of Character;
  77.    Work_String  : Work_String_Type;
  78.    WS_Length    : Natural := 0;
  79.    WS_Index1    : Natural := 0;
  80.    WS_Index2    : Natural := 0;
  81.    Tmp          : String (1 .. 1024);
  82.  
  83.    ------------------------
  84.    --  Local Subprograms --
  85.    ------------------------
  86.  
  87.    procedure Allocate_AFCB;
  88.    --  Determine which AFCB in the Open_Files table is available to be used
  89.    --  for the current file.
  90.  
  91.    function Alpha (C : Character) return Boolean;
  92.    --  Predicate to test if Character argument is an upper or lower case
  93.    --  letter, returns True if the argument is a letter, False if not.
  94.  
  95.    function Alphanum (C : Character) return Boolean;
  96.    --  Predicate to test if Character is an upper or lower case letter
  97.    --  or a digit. Returns True if the arguement is a letter or a digit,
  98.    --  False if not.
  99.  
  100.    function Char1 return Character;
  101.    function Char2 return Character;
  102.    function Char3 return Character;
  103.    --  Obtain indicated character of lookahead
  104.  
  105.    function Chars return Integer;
  106.    --  Obtain count field from file
  107.  
  108.    procedure Check_Digit;
  109.    --  Assert that the next Character is a digit otherwise raise Data_Error.
  110.  
  111.    procedure Check_Extended_Digit;
  112.    --  Assert that the next Character is an extended digit otherwise raise
  113.    --  Data_Error.
  114.  
  115.    procedure Check_File_Open;
  116.    --  Check if the current file is open or not. If the file is not open,
  117.    --  then Status_Error is raised. Otherwise control returns normally.
  118.  
  119.    procedure Check_Hash (C : Character);
  120.    --  Determine if next Character is matching hash, raise Data_Error if not.
  121.    --  Stores '#' in Work_String.
  122.  
  123.    procedure Check_Multiple_File_Opens;
  124.  
  125.    procedure Check_Opened_Ok;
  126.    --  Check that an Fopen succeeded, raise Name_Error if not
  127.  
  128.    procedure Check_Status_And_Mode (C_Mode : File_Mode);
  129.    --  If the current file is not open, then Status_Error is raised. If
  130.    --  the file is open, then the mode is checked against the argument which
  131.    --  is the desired mode for the operation. If it does not match, then
  132.    --  Mode_Error is raised, otherwise control returns normally.
  133.  
  134.    procedure Check_Status_And_Mode (C_Mode1, C_Mode2 : File_Mode);
  135.    --  If the current file is not open, then Status_Error is raised. If
  136.    --  the file is open, then the mode is checked against the arguments which
  137.    --  are the desired modes for the operation. If it does not match either
  138.    --  one of them, Mode_Error is raised, otherwise control returns normally.
  139.  
  140.    procedure Close_File;
  141.    --  Close file and deallocate the AFCB back to the pool.
  142.  
  143.    procedure Copy_Integer;
  144.    --  This procedure copies a string with the syntax of "based_Integer" from
  145.    --  the input to the Work_String. Underscores are allowed but not copied.
  146.  
  147.    procedure Copy_Based_Integer;
  148.    --  This procedure copies a string with the syntax of "based_Integer" from
  149.    --  the input to the Work_String. Underscores are allowed but not copied.
  150.  
  151.    procedure Copyc;
  152.    --  Copy the next input Character to Work_String using WS_Index2
  153.  
  154.    function Digit (C : Character) return Boolean;
  155.    --  Predicate if C corresponds to the digits 0 thru 9.
  156.  
  157.    function Extended_Digit (C : Character) return Boolean;
  158.    --  Predicate if C corresponds to the digits 0 thru 9 or letters A thru F.
  159.  
  160.    function Graphic (C : Character) return Boolean;
  161.    --  Predicate to test if the Character is a Latin-1 graphic letter.
  162.    --  True if the argument is a Latin-1 graphic character, False otherwise.
  163.  
  164.    function Getcp return Character;
  165.    --  Gets the next Character from the string or file being scanned according
  166.    --  to the setting of Scanning_From_File. In string mode, WS_Index1 is
  167.    --  updated. If no more Characters remain to be scanned, End_Error is
  168.    --  raised.
  169.  
  170.    function Get_Char return Character;
  171.    --  Get the next character from the current text input file. If no
  172.    --  character is available, End_Error is raised.
  173.  
  174.    function  Is_Keyboard (F : Text_IO.File_Type) return Boolean;
  175.    --  Indicates whether the input represents a tty (keyboard) rather than
  176.    --  a stored file.
  177.    pragma Inline (Is_Keyboard);
  178.  
  179.    procedure Make_Temp_File_Name;
  180.    --  Generate a unique file name and use it for the name of the current file.
  181.  
  182.    function Nextc return Character;
  183.    --  Return the next Character to be read from the string file being
  184.    --  scanned, according to the setting of Scanning_From_File. In string
  185.    --  mode WS_Index1 is updated. If we are currently at the end of string
  186.    --  then a line feed is returned.
  187.  
  188.    function Page_Is_Not_Terminated return Boolean;
  189.    --  Indicates whether the current page of current file is not terminated.
  190.  
  191.    procedure Put_Blanks (N : Integer);
  192.    --  Write N blanks to the output. There is no check for line overflow, it
  193.    --  is assumed that the caller has already checked for this.
  194.  
  195.    procedure Put_Buffer
  196.      (Width    : Integer;
  197.       Pad_Type : Character;
  198.       Length : Integer);
  199.    --  Need documentation ???
  200.  
  201.    procedure Put_Line1;
  202.    --  Outputs a line feed to the current text file
  203.  
  204.    procedure Put_Page;
  205.    --  Write a page mark to current text file.
  206.  
  207.    procedure Load_Look_Ahead (End_Of_File_Flag : Boolean);
  208.    --  This procedure loads the lookahead for a TEXT_IO input file, leaving
  209.    --  CHARS set to 3 (unless the file is less than 3 bytes long), and CHAR1
  210.    --  CHAR2 and CHAR3 containing the initial characters of the file. A special
  211.    --  exception occurs when the standard input file is the keyboard in which
  212.    --  case we only read 1 character because of interactive I/O except when
  213.    --  load_look_ahead is called in the case of END_OF_FILE where we want to
  214.    --  read 2 characters to check for the EOT character. The parameter to this
  215.    --  routine end_of_file_flag is TRUE when processing for and END_OF_FILE
  216.    --  situation and is FALSE otherwise.
  217.  
  218.    procedure Range_Error;
  219.    --  Procedure called if scanned number is out of range.
  220.  
  221.    function Scan_Based_Int (Base : Integer) return Integer;
  222.    --  Need documentation ???
  223.  
  224.    procedure Scan_Blanks;
  225.    --  Routine to scan past leading blanks to find first non-blank.
  226.    --  Leaves WS_Index1 pointing to first non-blank character.
  227.  
  228.    procedure Scan_Enum (Last : out Natural);
  229.    --  Procedure to scan an Ada enumeration literal, which maybe an identifier
  230.    --  or a character literal. The input may be from a file or from a string
  231.    --  depending the setting of the Scanning_From_File flag. The result is
  232.    --  stored in Work_String.
  233.  
  234.    function Scan_Int return Integer;
  235.    --  This routine scans an Integer value from the string pointed by the
  236.    --  global Integer WS_Index2. On exit WS_Index2 is updated to point to
  237.    --  the first
  238.    --  non-digit. The result returned is always negative. This allows the
  239.    --  largest negative Integer value to be properly stored and converted.
  240.    --  A value of +1 returned indicated that overflow occured.
  241.  
  242.    procedure Scan_Integer (Width : Integer; Result : out Integer);
  243.    --  Procedure to scan an Ada Integer value and return the Integer result
  244.    --  The parameter Width specifies the width of the field (zero means an
  245.    --  unlimited scan). The input is from the current TEXT_IO input file.
  246.  
  247.    procedure Scan_Integer_Val (Fixed_Field : Boolean; Result : out Integer);
  248.    --  Procedure to scan an Ada Integer value and return the Integer result.
  249.  
  250.    function Scan_Float (Width : Natural) return LLF;
  251.    --  Procedure to scan an Ada float value and return the float result.
  252.    --  The width specifies the width of the field(zero = unlimited scan).
  253.    --  For this case, the input is from the current TEXT_IO input file.
  254.  
  255.    function Scan_Float_Val (Fixed_Field : Boolean) return LLF;
  256.    --  Procedure to scan an Ada float value and return the float result. The
  257.    --  parameter num_type is a pointer to the type template for the float type.
  258.  
  259.    function Scan_Real_Val (Fixed_Field : Boolean) return LLF;
  260.    --  Procedure to scan a real value and return the result as a double real.
  261.    --  A range exception is signalled if the value is out of range of allowed
  262.    --  Ada real values, but no other range check is made.
  263.  
  264.    procedure Set_Char1 (Val : Character);
  265.    procedure Set_Char2 (Val : Character);
  266.    procedure Set_Char3 (Val : Character);
  267.    --  Set indicated character of lookahead to given character
  268.  
  269.    procedure Set_Chars (Val : Integer);
  270.    --  Set count field of file to indicated value
  271.  
  272.    procedure Setup_Fixed_Field (Width : Integer);
  273.    --  This procedure is used for numeric conversions where the field to be
  274.    --  scanned has a fixed width (i.e. width parameter is non-zero).
  275.    --  It acquires the field from the input file and copies it to Work_String.
  276.    --  It returns to the caller ready to scan the data from work_string.
  277.  
  278.    function Sign (C : Character) return Boolean;
  279.    --  Predicate indicating whether character C is '+' or '-'
  280.  
  281.    procedure Skipc;
  282.    --  This procedure skips the next input Character.
  283.  
  284.    procedure Test_Fixed_Field_End;
  285.    --  this procedure is called after scanning an item from a fixed length
  286.    --  field to ensure that only blanks remain in the field. An exception
  287.    --  is raised if there are any unexpected non-blank Characters left in
  288.    --  the field.
  289.  
  290.    function Upper_Case (C : Character) return Character;
  291.    --  Converts character C to upper case if necessary
  292.  
  293.    procedure Unimplemented (Message : String);
  294.    --  Output message for unimplemented feature
  295.  
  296.    procedure Word_Mul
  297.      (A : Integer;
  298.       B : Integer;
  299.       O : out Boolean;
  300.       R : out Integer);
  301.    --  Multiply with overflow check (use until trapping arithmetic works).
  302.  
  303.    procedure Word_Sub
  304.      (A : Integer;
  305.       B : Integer;
  306.       O : out Boolean;
  307.       R : out Integer);
  308.    --  Subtraction with overflow check (use until trapping arithmetic works)
  309.  
  310.    --  Interface with system calls
  311.  
  312.    procedure C_Fgetc
  313.      (F      : Text_IO.File_Ptr;
  314.       C      : out Character;
  315.       Is_Eof : out Boolean);
  316.  
  317.    procedure Fclose (P : Text_IO.File_Ptr);
  318.  
  319.    function  Fopen (Name : String; Typ : File_Mode) return Text_IO.File_Ptr;
  320.  
  321.    procedure Fputc (F : Text_IO.File_Ptr; C : Character);
  322.  
  323.    function  Isatty (F : Text_IO.File_Ptr) return Boolean;
  324.  
  325.    function  Stdin return Text_IO.File_Ptr;
  326.  
  327.    function  Stdout return Text_IO.File_Ptr;
  328.  
  329.    function  Stderr return Text_IO.File_Ptr;
  330.  
  331.    procedure Unlink (Name : String);
  332.  
  333.    -----------
  334.    -- Chars --
  335.    -----------
  336.  
  337.    function Chars return Integer is
  338.    begin
  339.       return The_File.Count;
  340.    end Chars;
  341.  
  342.    ---------------
  343.    -- Set_Chars --
  344.    ---------------
  345.  
  346.    procedure Set_Chars (Val : Integer) is
  347.    begin
  348.       The_File.Count := Val;
  349.    end Set_Chars;
  350.  
  351.    -----------
  352.    -- Char1 --
  353.    -----------
  354.  
  355.    function Char1 return Character is
  356.    begin
  357.       return The_File.Look_Ahead (1);
  358.    end Char1;
  359.  
  360.    ---------------
  361.    -- Set_Char1 --
  362.    ---------------
  363.  
  364.    procedure Set_Char1 (Val : Character) is
  365.    begin
  366.       The_File.Look_Ahead (1) := Val;
  367.    end Set_Char1;
  368.  
  369.    -----------
  370.    -- Char2 --
  371.    -----------
  372.  
  373.    function Char2 return Character is
  374.    begin
  375.       return The_File.Look_Ahead (2);
  376.    end Char2;
  377.  
  378.    ---------------
  379.    -- Set_Char2 --
  380.    ---------------
  381.  
  382.    procedure Set_Char2 (Val : Character) is
  383.    begin
  384.       The_File.Look_Ahead (2) := Val;
  385.    end Set_Char2;
  386.  
  387.    -----------
  388.    -- Char3 --
  389.    -----------
  390.  
  391.    function Char3 return Character is
  392.    begin
  393.       return The_File.Look_Ahead (3);
  394.    end Char3;
  395.  
  396.    ---------------
  397.    -- Set_Char3 --
  398.    ---------------
  399.  
  400.    procedure Set_Char3 (Val : Character) is
  401.    begin
  402.       The_File.Look_Ahead (3) := Val;
  403.    end Set_Char3;
  404.  
  405.    ------------
  406.    -- Create --
  407.    ------------
  408.  
  409.    procedure Create
  410.      (File : in out File_Type;
  411.       Mode : in File_Mode := Out_File;
  412.       Name : in String := "";
  413.       Form : in String := "") is
  414.  
  415.    begin
  416.       The_File := File;
  417.  
  418.       if The_File /= null then
  419.          raise Status_Error; --  File already open
  420.       elsif Mode = In_File then
  421.          raise Use_Error;    -- Unsupported file access
  422.       end if;
  423.  
  424.       Allocate_AFCB;
  425.       The_File.Name := new String'(Name);
  426.       The_File.Form := new String'(Form);
  427.       The_File.Mode := Mode;
  428.  
  429.       if Name'Length = 0 then
  430.          Make_Temp_File_Name;
  431.       end if;
  432.  
  433.       Check_Multiple_File_Opens;
  434.       The_File.AFCB_In_Use := True;
  435.       The_File.Desc := Fopen (The_File.Name.all, Mode);
  436.       Check_Opened_Ok;
  437.  
  438.       The_File.Page := 1;
  439.       The_File.Line := 1;
  440.       The_File.Col := 1;
  441.       The_File.Line_Length := 0;
  442.       The_File.Page_Length := 0;
  443.       File := The_File;
  444.    end Create;
  445.  
  446.    ----------
  447.    -- Open --
  448.    ----------
  449.  
  450.    procedure Open
  451.      (File : in out File_Type;
  452.       Mode : in File_Mode;
  453.       Name : in String;
  454.       Form : in String := "")
  455.    is
  456.    begin
  457.       The_File := File;
  458.  
  459.       if The_File /= null then
  460.          raise Status_Error; --  File already open
  461.       end if;
  462.  
  463.       Allocate_AFCB;
  464.       The_File.Name := new String'(Name);
  465.       The_File.Form := new String'(Form);
  466.       The_File.Mode := Mode;
  467.  
  468.       if Name'Length = 0 then
  469.          Make_Temp_File_Name;
  470.       end if;
  471.  
  472.       Check_Multiple_File_Opens;
  473.       The_File.AFCB_In_Use := True;
  474.  
  475.       The_File.Desc := Fopen (Name, Mode);
  476.       Check_Opened_Ok;
  477.       if Mode = In_File then
  478.          Set_Chars (0);
  479.       end if;
  480.  
  481.       The_File.Page := 1;
  482.       The_File.Line := 1;
  483.       The_File.Col := 1;
  484.       The_File.Line_Length := 0;
  485.       The_File.Page_Length := 0;
  486.       The_File.Is_Keyboard := False;
  487.       File := The_File;
  488.    end Open;
  489.  
  490.    -----------
  491.    -- Close --
  492.    -----------
  493.  
  494.    procedure Close (File : in out File_Type) is
  495.    begin
  496.       The_File := File;
  497.       Check_File_Open;
  498.  
  499.       if The_File.Mode = Out_File or else The_File.Mode = Append_File then
  500.  
  501.          --  Simulate effect of NEW_PAGE unless current page is terminated
  502.  
  503.          if Page_Is_Not_Terminated then
  504.             if The_File.Col > 1
  505.               or else (The_File.Col = 1 and then The_File.Line = 1)
  506.             then
  507.                Put_Line1;
  508.             end if;
  509.  
  510.             Put_Page;
  511.          end if;
  512.       end if;
  513.  
  514.       --  If the file being closed is one of the default files, set the default
  515.       --  file indicator to null to indicate that the file is closed.
  516.  
  517.       if The_File = Current_In then
  518.          Current_In := null;
  519.       elsif The_File = Current_Out then
  520.          Current_Out := null;
  521.       elsif The_File = Current_Err then
  522.          Current_Err := null;
  523.       end if;
  524.  
  525.       --  Sever the association between the given file and its associated
  526.       --  external file. The given file is left closed. Do not perform system
  527.       --  closes on the standard input, output and error files.
  528.  
  529.       if The_File /= Standard_In
  530.         and then The_File /= Standard_Out
  531.         and then The_File /= Standard_Err
  532.       then
  533.          Close_File;
  534.       end if;
  535.  
  536.       The_File := null;
  537.       File := The_File;
  538.    end Close;
  539.  
  540.    ------------
  541.    -- Delete --
  542.    ------------
  543.  
  544.    procedure Delete (File : in out File_Type) is
  545.       File_Name_To_Delete : Pstring;
  546.  
  547.    begin
  548.       The_File := File;
  549.       Check_File_Open;
  550.       File_Name_To_Delete := new String'(The_File.Name.all);
  551.       Close (The_File);
  552.       Unlink (File_Name_To_Delete.all);
  553.       File := The_File;
  554.    end Delete;
  555.  
  556.    -----------
  557.    -- Reset --
  558.    -----------
  559.  
  560.    procedure Reset
  561.      (File : in out File_Type;
  562.       Mode : in File_Mode)
  563.    is
  564.    begin
  565.       The_File := File;
  566.       Check_File_Open;
  567.  
  568.       if (The_File = Current_In
  569.            or else The_File = Current_Out
  570.            or else The_File = Current_Err)
  571.         and then The_File.Mode /= Mode
  572.       then
  573.          raise Mode_Error;  --  "Cannot change mode"
  574.       end if;
  575.  
  576.       if The_File.Mode = Out_File or else The_File.Mode = Append_File then
  577.  
  578.          --  Simulate NEW_PAGE unless current page already terminated
  579.  
  580.          if Page_Is_Not_Terminated then
  581.             if The_File.Col > 1
  582.               or else (The_File.Col = 1 and then The_File.Line = 1)
  583.             then
  584.                Put_Line1;
  585.             end if;
  586.  
  587.             Put_Page;
  588.          end if;
  589.       end if;
  590.  
  591.       Fclose (The_File.Desc);
  592.  
  593.       The_File.Desc := Fopen (The_File.Name.all, Mode);
  594.       Check_Opened_Ok;
  595.  
  596.       if Mode /= In_File then
  597.          The_File.Line_Length := 0;
  598.          The_File.Page_Length := 0;
  599.       end if;
  600.  
  601.       The_File.Mode := Mode;
  602.       Set_Chars (0);
  603.       The_File.Col  := 1;
  604.       The_File.Line := 1;
  605.       The_File.Page := 1;
  606.       File := The_File;
  607.    end Reset;
  608.  
  609.    ----------
  610.    -- Mode --
  611.    ----------
  612.  
  613.    function Mode (File : in File_Type) return File_Mode is
  614.    begin
  615.       The_File := File;
  616.       Check_File_Open;
  617.       return The_File.Mode;
  618.    end Mode;
  619.  
  620.    ----------
  621.    -- Name --
  622.    ----------
  623.  
  624.    function Name (File : in File_Type) return String is
  625.    begin
  626.       The_File := File;
  627.       Check_File_Open;
  628.       return The_File.Name.all;
  629.    end Name;
  630.  
  631.    ----------
  632.    -- Form --
  633.    ----------
  634.  
  635.    function Form (File : in File_Type) return String is
  636.    begin
  637.       The_File := File;
  638.       Check_File_Open;
  639.       return The_File.Form.all;
  640.    end Form;
  641.  
  642.    -------------
  643.    -- Is_Open --
  644.    -------------
  645.  
  646.    function Is_Open (File : in File_Type) return Boolean is
  647.    begin
  648.       The_File := File;
  649.       return The_File /= null;
  650.    end Is_Open;
  651.  
  652.    ---------------
  653.    -- Set_Input --
  654.    ---------------
  655.  
  656.    procedure Set_Input (File : in File_Type) is
  657.    begin
  658.       The_File := File;
  659.       Check_Status_And_Mode (In_File);
  660.       Current_In := The_File;
  661.    end Set_Input;
  662.  
  663.    ----------------
  664.    -- Set_Output --
  665.    ----------------
  666.  
  667.    procedure Set_Output (File : in File_Type) is
  668.    begin
  669.       The_File := File;
  670.       Check_Status_And_Mode (Out_File, Append_File);
  671.       Current_Out := The_File;
  672.    end Set_Output;
  673.  
  674.    ---------------
  675.    -- Set_Error --
  676.    ---------------
  677.  
  678.    procedure Set_Error (File : in File_Type) is
  679.    begin
  680.       The_File := File;
  681.       Check_Status_And_Mode (Out_File, Append_File);
  682.       Current_Err := The_File;
  683.    end Set_Error;
  684.  
  685.    --------------------
  686.    -- Standard_Input --
  687.    --------------------
  688.  
  689.    function Standard_Input return File_Type is
  690.    begin
  691.       return Standard_In;
  692.    end Standard_Input;
  693.  
  694.    ---------------------
  695.    -- Standard_Output --
  696.    ---------------------
  697.  
  698.    function Standard_Output return File_Type is
  699.    begin
  700.       return Standard_Out;
  701.    end Standard_Output;
  702.  
  703.    --------------------
  704.    -- Standard_Error --
  705.    --------------------
  706.  
  707.    function Standard_Error return File_Type is
  708.    begin
  709.       return Standard_Err;
  710.    end Standard_Error;
  711.  
  712.    -------------------
  713.    -- Current_Input --
  714.    -------------------
  715.  
  716.    function Current_Input return File_Type is
  717.    begin
  718.       return Current_In;
  719.    end Current_Input;
  720.  
  721.    --------------------
  722.    -- Current_Output --
  723.    --------------------
  724.  
  725.    function Current_Output return File_Type is
  726.    begin
  727.       return Current_Out;
  728.    end Current_Output;
  729.  
  730.    -------------------
  731.    -- Current_Error --
  732.    -------------------
  733.  
  734.    function Current_Error return File_Type is
  735.    begin
  736.       return Current_Err;
  737.    end Current_Error;
  738.  
  739.    ---------------------
  740.    -- Set_Line_Length --
  741.    ---------------------
  742.  
  743.    procedure Set_Line_Length (File : in File_Type; To : in Count) is
  744.    begin
  745.       The_File := File;
  746.       Check_Status_And_Mode (Out_File, Append_File);
  747.       The_File.Line_Length := To;
  748.    end Set_Line_Length;
  749.  
  750.    -----------------
  751.    -- Line_Length --
  752.    -----------------
  753.  
  754.    function Line_Length (File : in File_Type) return Count is
  755.    begin
  756.       The_File := File;
  757.       Check_Status_And_Mode (Out_File, Append_File);
  758.       return The_File.Line_Length;
  759.    end Line_Length;
  760.  
  761.    ---------------------
  762.    -- Set_Page_Length --
  763.    ---------------------
  764.  
  765.    procedure Set_Page_Length (File : in File_Type; To : in Count) is
  766.    begin
  767.       The_File := File;
  768.       Check_Status_And_Mode (Out_File, Append_File);
  769.       The_File.Page_Length := To;
  770.    end Set_Page_Length;
  771.  
  772.    -----------------
  773.    -- Page_Length --
  774.    -----------------
  775.  
  776.    function Page_Length (File : in File_Type) return Count is
  777.    begin
  778.       The_File := File;
  779.       Check_Status_And_Mode (Out_File, Append_File);
  780.       return The_File.Page_Length;
  781.    end Page_Length;
  782.  
  783.    --------------
  784.    -- New_Line --
  785.    --------------
  786.  
  787.    procedure New_Line
  788.      (File    : in File_Type;
  789.       Spacing : in Positive_Count := 1)
  790.    is
  791.    begin
  792.       The_File := File;
  793.       Check_Status_And_Mode (Out_File, Append_File);
  794.  
  795.       for J in 1 .. Spacing loop
  796.          Put_Line1;
  797.       end loop;
  798.    end New_Line;
  799.  
  800.    ---------------
  801.    -- Skip_Line --
  802.    ---------------
  803.  
  804.    procedure Skip_Line
  805.      (File    : in File_Type;
  806.       Spacing : in Positive_Count := 1)
  807.    is
  808.       C : Character;
  809.  
  810.    begin
  811.       The_File := File;
  812.       Check_Status_And_Mode (In_File);
  813.  
  814.       for J in 1 .. Spacing loop
  815.          loop
  816.             Load_Look_Ahead (False);
  817.             exit when Get_Char = Line_Feed;
  818.          end loop;
  819.  
  820.          --  Ignore page marks when reading from a terminal.
  821.  
  822.          if Is_Keyboard (The_File) then
  823.             return;
  824.          end if;
  825.  
  826.          loop
  827.             Load_Look_Ahead (False);
  828.             exit when Char1 /= Page_Mark;
  829.             C := Get_Char;
  830.          end loop;
  831.       end loop;
  832.    end Skip_Line;
  833.  
  834.    -----------------
  835.    -- End_Of_Line --
  836.    -----------------
  837.  
  838.    function End_Of_Line (File : in File_Type) return boolean is
  839.    begin
  840.       The_File := File;
  841.       Check_Status_And_Mode (In_File);
  842.       Load_Look_Ahead (False);
  843.       return Chars = 0 or else Char1 = Line_Feed;
  844.    end End_Of_Line;
  845.  
  846.    --------------
  847.    -- New_Page --
  848.    --------------
  849.  
  850.    procedure New_Page (File : in File_Type) is
  851.    begin
  852.       The_File := File;
  853.       Check_Status_And_Mode (Out_File, Append_File);
  854.  
  855.       if The_File.Col > 1
  856.        or else (The_File.Col = 1 and then The_File.Line = 1)
  857.       then
  858.          Put_Line1;
  859.       end if;
  860.  
  861.       Put_Page;
  862.    end New_Page;
  863.  
  864.    ---------------
  865.    -- Skip_Page --
  866.    ---------------
  867.  
  868.    procedure Skip_Page (File : in File_Type) is
  869.    begin
  870.       The_File := File;
  871.       Check_Status_And_Mode (In_File);
  872.  
  873.       while Get_Char /= Page_Mark loop
  874.          null;
  875.       end loop;
  876.    end Skip_Page;
  877.  
  878.    -----------------
  879.    -- End_Of_Page --
  880.    -----------------
  881.  
  882.    function End_Of_Page (File : in File_Type) return Boolean is
  883.    begin
  884.       The_File := File;
  885.       Check_Status_And_Mode (In_File);
  886.  
  887.       if Is_Keyboard (The_File) then
  888.          return False;
  889.       end if;
  890.  
  891.       Load_Look_Ahead (False);
  892.  
  893.       if Chars > 1 then
  894.          return Char1 = Line_Feed and then Char2 = Page_Mark;
  895.       elsif Chars = 1 then
  896.          return Char1 = Line_Feed;
  897.       else
  898.          return True;
  899.       end if;
  900.    end End_Of_Page;
  901.  
  902.    -----------------
  903.    -- End_Of_File --
  904.    -----------------
  905.  
  906.    function End_Of_File (File : in File_Type) return Boolean is
  907.    begin
  908.       The_File := File;
  909.       Check_Status_And_Mode (In_File);
  910.       Load_Look_Ahead (True);
  911.  
  912.       if Is_Keyboard (The_File) then
  913.          if Chars = 2 then
  914.             return False;
  915.          elsif Chars = 1 then
  916.             return Char1 = Line_Feed;
  917.          elsif Chars = 0 then
  918.             return True;
  919.          end if;
  920.       else
  921.          if Chars = 2 then
  922.             return Char1 = Line_Feed and then Char2 = Page_Mark;
  923.          elsif Chars = 1 then
  924.             return Char1 = Line_Feed;
  925.          elsif Chars = 0 then
  926.             return True;
  927.          else --  Chars = 3
  928.             return False;
  929.          end if;
  930.       end if;
  931.    end End_Of_File;
  932.  
  933.    -------------
  934.    -- Set_Col --
  935.    -------------
  936.  
  937.    procedure Set_Col (File : in File_Type; To : in Positive_Count) is
  938.       C : Character;
  939.  
  940.    begin
  941.       The_File := File;
  942.       Check_File_Open;
  943.  
  944.       if The_File.Mode = In_File then
  945.  
  946.          --  SET_COL for file of mode In_File
  947.  
  948.          Load_Look_Ahead (False);
  949.  
  950.          while The_File.Col /= To
  951.            or else Char1 = Line_Feed
  952.            or else Char1 = Page_Mark
  953.          loop
  954.             C := Get_Char;
  955.          end loop;
  956.  
  957.       else
  958.  
  959.          --  SET_COL for file of mode Out_File or Append_File
  960.  
  961.          if The_File.Line_Length > 0
  962.            and then To > The_File.Line_Length
  963.          then
  964.             raise Layout_Error; --  "SET_COL past end of line"
  965.          end if;
  966.  
  967.          if To > The_File.Col then
  968.             Put_Blanks (Integer (To - The_File.Col));
  969.             The_File.Col := To;
  970.          elsif To < The_File.Col then
  971.             Put_Line1;
  972.             Put_Blanks (Integer (To - 1));
  973.             The_File.Col := To;
  974.          end if;
  975.       end if;
  976.    end Set_Col;
  977.  
  978.    --------------
  979.    -- Set_Line --
  980.    --------------
  981.  
  982.    procedure Set_Line (File : in File_Type; To : in Positive_Count) is
  983.       C : Character;
  984.  
  985.    begin
  986.       The_File := File;
  987.       Check_File_Open;
  988.  
  989.       if The_File.Mode = In_File then
  990.  
  991.          --  SET_LINE for file of mode In_File
  992.  
  993.          Load_Look_Ahead (False);
  994.  
  995.          while The_File.Line /= To
  996.            or else Char1 = Page_Mark
  997.          loop
  998.             C := Get_Char;
  999.          end loop;
  1000.  
  1001.       else
  1002.  
  1003.          --  SET_LINE for file of mode Out_File or Append_File
  1004.  
  1005.          if The_File.Page_Length > 0
  1006.            and then To > The_File.Page_Length
  1007.          then
  1008.             raise Layout_Error;  --  "Set_Line > Page_Length"
  1009.          end if;
  1010.  
  1011.          if To > The_File.Line  then
  1012.             for I in 1 .. To - The_File.Line loop
  1013.                Put_Line1;
  1014.             end loop;
  1015.  
  1016.          elsif To < The_File.Line then
  1017.             if The_File.Col > 1
  1018.               or else (The_File.Col = 1 and then The_File.Line = 1)
  1019.             then
  1020.                Put_Line1;
  1021.             end if;
  1022.  
  1023.             Put_Page;
  1024.  
  1025.             for J in 1 .. To - 1 loop
  1026.                Put_Line1;
  1027.             end loop;
  1028.          end if;
  1029.       end if;
  1030.    end Set_Line;
  1031.  
  1032.    ---------
  1033.    -- Col --
  1034.    ---------
  1035.  
  1036.    function Col (File : in File_Type) return Positive_Count is
  1037.    begin
  1038.       The_File := File;
  1039.       Check_File_Open;
  1040.  
  1041.       if The_File.Col > Count'Last then
  1042.          raise Layout_Error; --  "Col > Count'Last"
  1043.       end if;
  1044.  
  1045.       return The_File.Col;
  1046.    end Col;
  1047.  
  1048.    ----------
  1049.    -- Line --
  1050.    ----------
  1051.  
  1052.    function Line (File : in File_Type) return Positive_Count is
  1053.    begin
  1054.       The_File := File;
  1055.       Check_File_Open;
  1056.  
  1057.       if The_File.Line > Count'Last then
  1058.          raise Layout_Error; --  "Line > Count'Last"
  1059.       end if;
  1060.  
  1061.       return The_File.Line;
  1062.    end Line;
  1063.  
  1064.    ----------
  1065.    -- Page --
  1066.    ----------
  1067.  
  1068.    function Page (File : in File_Type) return Positive_Count is
  1069.    begin
  1070.       The_File := File;
  1071.       Check_File_Open;
  1072.  
  1073.       if The_File.Page > Count'Last then
  1074.          raise Layout_Error; --  "Page > Count'Last"
  1075.       end if;
  1076.  
  1077.       return The_File.Page;
  1078.    end Page;
  1079.  
  1080.    ---------
  1081.    -- Get --
  1082.    ---------
  1083.  
  1084.    procedure Get (Item : out Character) is
  1085.    begin
  1086.       Check_Status_And_Mode (In_File);
  1087.  
  1088.       loop
  1089.          Item := Get_Char;
  1090.          exit when Item /= Page_Mark and then Item /= Line_Feed;
  1091.       end loop;
  1092.    end Get;
  1093.  
  1094.    ---------
  1095.    -- Put --
  1096.    ---------
  1097.  
  1098.    procedure Put (Item : in Character) is
  1099.    begin
  1100.       Check_Status_And_Mode (Out_File, Append_File);
  1101.  
  1102.       if The_File.Line_Length /= 0
  1103.         and then The_File.Col > The_File.Line_Length
  1104.       then
  1105.          Put_Line1;
  1106.       end if;
  1107.  
  1108.       Fputc (The_File.Desc, Item);
  1109.       The_File.Col := The_File.Col + 1;
  1110.    end Put;
  1111.  
  1112.    ---------
  1113.    -- Get --
  1114.    ---------
  1115.  
  1116.    procedure Get (Item : out String) is
  1117.       J : Integer := 0;
  1118.       C : Character;
  1119.  
  1120.    begin
  1121.       Check_Status_And_Mode (In_File);
  1122.  
  1123.       while J < Item'Length loop
  1124.          C := Get_Char;
  1125.  
  1126.          if C /= Line_Feed and then C /= Page_Mark then
  1127.             Item (Item'First + J) := C;
  1128.             J := J + 1;
  1129.          end if;
  1130.       end loop;
  1131.    end Get;
  1132.  
  1133.    ---------
  1134.    -- Put --
  1135.    ---------
  1136.  
  1137.    procedure Put (Item : in String) is
  1138.    begin
  1139.       for J in Item'Range loop
  1140.          Put (Item (J));
  1141.       end loop;
  1142.    end Put;
  1143.  
  1144.    --------------
  1145.    -- Put_Line --
  1146.    --------------
  1147.  
  1148.    procedure Put_Line (File : in File_Type; Item : in String) is
  1149.    begin
  1150.       The_File := File;
  1151.       Put (Item);
  1152.       New_Line (File, 1);
  1153.    end Put_Line;
  1154.  
  1155.    --------------
  1156.    -- Get_Line --
  1157.    --------------
  1158.  
  1159.    procedure Get_Line
  1160.      (File : in File_Type;
  1161.       Item : out String;
  1162.       Last : out Natural)
  1163.    is
  1164.       I_Length : Integer := Item'Length;
  1165.       Nstore   : Integer := 0;
  1166.  
  1167.    begin
  1168.       The_File := File;
  1169.       Check_Status_And_Mode (In_File);
  1170.  
  1171.       loop
  1172.          Load_Look_Ahead (False);
  1173.          exit when Nstore = I_Length;
  1174.  
  1175.          if Char1 = Line_Feed then
  1176.             Skip_Line (File, 1);
  1177.             exit;
  1178.          end if;
  1179.  
  1180.          Item (Item'First + Nstore) := Get_Char;
  1181.          Nstore := Nstore + 1;
  1182.       end loop;
  1183.  
  1184.       Last := Item'First + Nstore - 1;
  1185.    end Get_Line;
  1186.  
  1187.    -------------
  1188.    -- Get_Int --
  1189.    -------------
  1190.  
  1191.    procedure Get_Int
  1192.      (Item  : out Integer;
  1193.       Width : in Field := 0)
  1194.    is
  1195.    begin
  1196.       Check_Status_And_Mode (In_File);
  1197.       Scan_Integer (Width, Item);
  1198.    end Get_Int;
  1199.  
  1200.    -----------------
  1201.    -- Put_Integer --
  1202.    -----------------
  1203.  
  1204.    procedure Put_Integer
  1205.      (Item  : in Integer;
  1206.       Width : in Field;
  1207.       Base  : in Number_Base)
  1208.    is
  1209.    begin
  1210.       Check_Status_And_Mode (Out_File, Append_File);
  1211.       WS_Length := 0;
  1212.  
  1213.       if Base = 10 and then Width = 0 then
  1214.          Set_Image_Integer (Item, Tmp, WS_Length);
  1215.       elsif Base = 10 then
  1216.          Set_Image_Width_Integer (Item, Width, Tmp, WS_Length);
  1217.       else
  1218.          Set_Image_Based_Integer (Item, Base, Width, Tmp, WS_Length);
  1219.       end if;
  1220.  
  1221.       for J in 1 .. WS_Length loop
  1222.          Work_String (J - 1) := Tmp (J);
  1223.       end loop;
  1224.  
  1225.       Put_Buffer (Width, 'L', WS_Length);
  1226.    end Put_Integer;
  1227.  
  1228.    -------------
  1229.    -- Put_LLI --
  1230.    -------------
  1231.  
  1232.    procedure Put_LLI
  1233.      (Item  : in LLI;
  1234.       Width : in Field;
  1235.       Base  : in Number_Base)
  1236.    is
  1237.    begin
  1238.       Check_Status_And_Mode (Out_File, Append_File);
  1239.       WS_Length := 0;
  1240.  
  1241.       if Base = 10 and then Width = 0 then
  1242.          Set_Image_Long_Long_Integer (Item, Tmp, WS_Length);
  1243.       elsif Base = 10 then
  1244.          Set_Image_Width_Long_Long_Integer (Item, Width, Tmp, WS_Length);
  1245.       else
  1246.          Set_Image_Based_Long_Long_Integer (Item, Base, Width, Tmp, WS_Length);
  1247.       end if;
  1248.  
  1249.       for J in 1 .. WS_Length loop
  1250.          Work_String (J - 1) := Tmp (J);
  1251.       end loop;
  1252.  
  1253.       Put_Buffer (Width, 'L', WS_Length);
  1254.    end Put_LLI;
  1255.  
  1256.    -------------
  1257.    -- Get_LLI --
  1258.    -------------
  1259.  
  1260.    procedure Get_LLI
  1261.      (From : in  String;
  1262.       Item : out LLI;
  1263.       Last : out Positive;
  1264.       Size : in  Positive)
  1265.    is
  1266.       Pos : aliased Integer := From'First;
  1267.  
  1268.    begin
  1269.       if Size > Integer'Size then
  1270.          Item := Scan_Long_Long_Integer (From, Pos'Access, From'Last);
  1271.       else
  1272.          Item := LLI (Scan_Integer (From, Pos'Access, From'Last));
  1273.       end if;
  1274.  
  1275.       Last := Pos - 1;
  1276.  
  1277.    exception
  1278.       when Constraint_Error =>
  1279.          if Pos > From'Last then
  1280.             raise End_Error;
  1281.          else
  1282.             raise Data_Error;
  1283.          end if;
  1284.    end Get_LLI;
  1285.  
  1286.    -------------
  1287.    -- Get_LLU --
  1288.    -------------
  1289.  
  1290.    procedure Get_LLU
  1291.      (From : in String;
  1292.       Item : out LLU;
  1293.       Last : out Positive;
  1294.       Size : in Positive)
  1295.    is
  1296.       Pos : aliased Integer := From'First;
  1297.  
  1298.    begin
  1299.       if Size > Unsigned'Size then
  1300.          Item := Scan_Long_Long_Unsigned (From, Pos'Access, From'Last);
  1301.       else
  1302.          Item := LLU (Scan_Unsigned (From, Pos'Access, From'Last));
  1303.       end if;
  1304.  
  1305.       Last := Pos - 1;
  1306.  
  1307.    exception
  1308.       when Constraint_Error =>
  1309.          if Pos > From'Last then
  1310.             raise End_Error;
  1311.          else
  1312.             raise Data_Error;
  1313.          end if;
  1314.    end Get_LLU;
  1315.  
  1316.    -----------------
  1317.    -- Put_Integer --
  1318.    -----------------
  1319.  
  1320.    procedure Put_Integer
  1321.      (To   : out String;
  1322.       Item : in Integer;
  1323.       Base : in Number_Base)
  1324.    is
  1325.       Length : Natural := 0;
  1326.       To_Len : Natural := To'Length;
  1327.  
  1328.    begin
  1329.       if Base = 10 then
  1330.          Set_Image_Width_Integer (Item, To_Len, Tmp, Length);
  1331.       else
  1332.          Set_Image_Based_Integer (Item, Base, To_Len, Tmp, Length);
  1333.       end if;
  1334.  
  1335.       if Length > To_Len then
  1336.          raise Layout_Error;
  1337.       end if;
  1338.  
  1339.       for J in 1 .. Length loop
  1340.          To (To'First + J - 1) := Tmp (J);
  1341.       end loop;
  1342.  
  1343.    end Put_Integer;
  1344.  
  1345.    -------------
  1346.    -- Put_LLI --
  1347.    -------------
  1348.  
  1349.    procedure Put_LLI
  1350.      (To   : out String;
  1351.       Item : in LLI;
  1352.       Base : in Number_Base)
  1353.    is
  1354.       Length : Natural := 0;
  1355.       To_Len : Natural := To'Length;
  1356.  
  1357.    begin
  1358.       if Base = 10 then
  1359.          Set_Image_Width_Long_Long_Integer (Item, To_Len, Tmp, Length);
  1360.       else
  1361.          Set_Image_Based_Long_Long_Integer (Item, Base, To_Len, Tmp, Length);
  1362.       end if;
  1363.  
  1364.       if Length > To_Len then
  1365.          raise Layout_Error;
  1366.       end if;
  1367.  
  1368.       for J in 1 .. Length loop
  1369.          To (To'First + J - 1) := Tmp (J);
  1370.       end loop;
  1371.  
  1372.    end Put_LLI;
  1373.  
  1374.    ------------------
  1375.    -- Put_Unsigned --
  1376.    ------------------
  1377.  
  1378.    procedure Put_Unsigned
  1379.      (Item  : in Unsigned;
  1380.       Width : in Field;
  1381.       Base  : in Number_Base)
  1382.    is
  1383.    begin
  1384.       Check_Status_And_Mode (Out_File, Append_File);
  1385.       WS_Length := 0;
  1386.  
  1387.       if Base = 10 and then Width = 0 then
  1388.          Set_Image_Unsigned (Item, Tmp, WS_Length);
  1389.       elsif Base = 10 then
  1390.          Set_Image_Width_Unsigned (Item, Width, Tmp, WS_Length);
  1391.       else
  1392.          Set_Image_Based_Unsigned (Item, Base, Width, Tmp, WS_Length);
  1393.       end if;
  1394.  
  1395.       for J in 1 .. WS_Length loop
  1396.          Work_String (J - 1) := Tmp (J);
  1397.       end loop;
  1398.  
  1399.       Put_Buffer (Width, 'L', WS_Length);
  1400.    end Put_Unsigned;
  1401.  
  1402.    -------------
  1403.    -- Put_LLU --
  1404.    -------------
  1405.  
  1406.    procedure Put_LLU
  1407.      (Item  : in LLU;
  1408.       Width : in Field;
  1409.       Base  : in Number_Base)
  1410.    is
  1411.    begin
  1412.       Check_Status_And_Mode (Out_File, Append_File);
  1413.       WS_Length := 0;
  1414.  
  1415.       if Base = 10 and then Width = 0 then
  1416.          Set_Image_Long_Long_Unsigned (Item, Tmp, WS_Length);
  1417.       elsif Base = 10 then
  1418.          Set_Image_Width_Long_Long_Unsigned (Item, Width, Tmp, WS_Length);
  1419.       else
  1420.          Set_Image_Based_Long_Long_Unsigned
  1421.            (Item, Base, Width, Tmp, WS_Length);
  1422.       end if;
  1423.  
  1424.       for J in 1 .. WS_Length loop
  1425.          Work_String (J - 1) := Tmp (J);
  1426.       end loop;
  1427.  
  1428.       Put_Buffer (Width, 'L', WS_Length);
  1429.    end Put_LLU;
  1430.  
  1431.    ------------------
  1432.    -- Put_Unsigned --
  1433.    ------------------
  1434.  
  1435.    procedure Put_Unsigned
  1436.      (To   : out String;
  1437.       Item : in Unsigned;
  1438.       Base : in Number_Base)
  1439.    is
  1440.       Length : Natural := 0;
  1441.       To_Len : Natural := To'Length;
  1442.  
  1443.    begin
  1444.       if Base = 10 then
  1445.          Set_Image_Width_Unsigned (Item, To_Len, Tmp, Length);
  1446.       else
  1447.          Set_Image_Based_Unsigned (Item, Base, To_Len, Tmp, Length);
  1448.       end if;
  1449.  
  1450.       if Length > To_Len then
  1451.          raise Layout_Error;
  1452.       end if;
  1453.  
  1454.       for J in 1 .. Length loop
  1455.          To (To'First + J - 1) := Tmp (J);
  1456.       end loop;
  1457.  
  1458.    end Put_Unsigned;
  1459.  
  1460.    -------------
  1461.    -- Put_LLU --
  1462.    -------------
  1463.  
  1464.    procedure Put_LLU
  1465.      (To   : out String;
  1466.       Item : in LLU;
  1467.       Base : in Number_Base)
  1468.    is
  1469.       Length : Natural := 0;
  1470.       To_Len : Natural := To'Length;
  1471.  
  1472.    begin
  1473.       if Base = 10 then
  1474.          Set_Image_Width_Long_Long_Unsigned (Item, To_Len, Tmp, Length);
  1475.       else
  1476.          Set_Image_Based_Long_Long_Unsigned (Item, Base, To_Len, Tmp, Length);
  1477.       end if;
  1478.  
  1479.       if Length > To_Len then
  1480.          raise Layout_Error;
  1481.       end if;
  1482.  
  1483.       for J in 1 .. Length loop
  1484.          To (To'First + J - 1) := Tmp (J);
  1485.       end loop;
  1486.    end Put_LLU;
  1487.  
  1488.    ---------------
  1489.    -- Get_Float --
  1490.    ---------------
  1491.  
  1492.    procedure Get_Float
  1493.      (Item : out LLF;
  1494.       Width : in Field)
  1495.    is
  1496.    begin
  1497.       Check_Status_And_Mode (In_File);
  1498.       Item := Scan_Float (Width);
  1499.    end Get_Float;
  1500.  
  1501.    ---------------
  1502.    -- Put_Float --
  1503.    ---------------
  1504.  
  1505.    procedure Put_Float
  1506.      (Item : in LLF;
  1507.       Fore : in Field;
  1508.       Aft  : in Field;
  1509.       Exp  : in Field)
  1510.    is
  1511.       Temp : String (1 .. 1024);
  1512.    begin
  1513.       Check_Status_And_Mode (Out_File, Append_File);
  1514.       WS_Length := 0;
  1515.       Set_Image_Real (Item, Temp, WS_Length, Fore, Aft, Exp);
  1516.  
  1517.       for J in 1 .. WS_Length loop
  1518.          Work_String (J - 1) := Temp (J);
  1519.       end loop;
  1520.  
  1521.       Put_Buffer (WS_Length, 'L', WS_Length);
  1522.    end Put_Float;
  1523.  
  1524.    ---------------
  1525.    -- Get_Float --
  1526.    ---------------
  1527.  
  1528.    procedure Get_Float
  1529.      (From : in String;
  1530.       Item : out LLF;
  1531.       Last : out Positive)
  1532.    is
  1533.       Pos : aliased Natural := From'First;
  1534.  
  1535.    begin
  1536.       Item := Scan_Real (From, Pos'Access, From'Last);
  1537.       Last := Pos - 1;
  1538.  
  1539.    exception
  1540.       when Constraint_Error =>
  1541.          if Pos > From'Last then
  1542.             raise End_Error;
  1543.          else
  1544.             raise Data_Error;
  1545.          end if;
  1546.    end Get_Float;
  1547.  
  1548.    ---------------
  1549.    -- Put_Float --
  1550.    ---------------
  1551.  
  1552.    procedure Put_Float
  1553.      (To   : out String;
  1554.       Item : in LLF;
  1555.       Aft  : in Field;
  1556.       Exp  : in Field)
  1557.    is
  1558.       Length : Natural := 0;
  1559.       To_Len : Natural := To'Length;
  1560.       Temp   : String (1 .. 1024);
  1561.       --  ??? what is the 1024 here? should be symbolic
  1562.  
  1563.    begin
  1564.       Set_Image_Real (Item, Temp, Length, 0, Aft, Exp);
  1565.  
  1566.       if Length > To_Len then
  1567.          raise Layout_Error;
  1568.       end if;
  1569.  
  1570.       for J in 0 .. To_Len - Length - 1 loop
  1571.          To (To'First + J) :=  ' ';
  1572.       end loop;
  1573.  
  1574.       for J in 1 .. Length loop
  1575.          To (To'First + J - 1 + To_Len - Length) := Temp (J);
  1576.       end loop;
  1577.  
  1578.    end Put_Float;
  1579.  
  1580.    --------------
  1581.    -- Get_Enum --
  1582.    --------------
  1583.  
  1584.    procedure Get_Enum (Str : out String; Len : out Positive) is
  1585.       Last : Natural;
  1586.  
  1587.    begin
  1588.       Check_Status_And_Mode (In_File);
  1589.       Scanning_From_File := True;
  1590.       Scan_Enum (Last);
  1591.  
  1592.       for J in 1 .. WS_Length loop
  1593.          Str (J) := Upper_Case (Work_String (J - 1));
  1594.       end loop;
  1595.  
  1596.       Len := WS_Length;
  1597.    end Get_Enum;
  1598.  
  1599.    --------------
  1600.    -- Get_Enum --
  1601.    --------------
  1602.  
  1603.    procedure Get_Enum
  1604.      (Str  : out String;
  1605.       From : in String;
  1606.       Len  : out Positive;
  1607.       Last : out Positive)
  1608.    is
  1609.    begin
  1610.       WS_Length := From'Length;
  1611.  
  1612.       for J in 0 .. WS_Length - 1 loop
  1613.          Work_String (J) := From (From'First + J);
  1614.       end loop;
  1615.  
  1616.       WS_Index1 := 0;
  1617.       Scanning_From_File := False;
  1618.       Scan_Enum (Last);
  1619.       Last := From'First + Last - 1;
  1620.  
  1621.       for J in 1 .. WS_Length loop
  1622.          Str (J) := Upper_Case (Work_String (J - 1));
  1623.       end loop;
  1624.  
  1625.       Len := WS_Length;
  1626.    end Get_Enum;
  1627.  
  1628.    --------------
  1629.    -- Put_Enum --
  1630.    --------------
  1631.  
  1632.    procedure Put_Enum
  1633.      (Item  : in String;
  1634.       Width : in Field;
  1635.       Set   : in Type_Set)
  1636.    is
  1637.       C : Character;
  1638.  
  1639.    begin
  1640.       Check_Status_And_Mode (Out_File, Append_File);
  1641.       WS_Length := Item'Length;
  1642.  
  1643.       for J in 0 .. WS_Length - 1 loop
  1644.          C := Item (Item'First + J);
  1645.  
  1646.          --  This is wrong, must use proper casing stuff in strings packages
  1647.          --  ???
  1648.  
  1649.          if Set = Lower_Case and then C in 'A' .. 'Z' then
  1650.             Work_String (J) := Character'Val (Character'Pos (C) + 32);
  1651.          else
  1652.             Work_String (J) := C;
  1653.          end if;
  1654.       end loop;
  1655.  
  1656.       Put_Buffer (Width, 'T', WS_Length);
  1657.    end Put_Enum;
  1658.  
  1659.    --------------
  1660.    -- Put_Enum --
  1661.    --------------
  1662.  
  1663.    procedure Put_Enum
  1664.      (To   : out String;
  1665.       Item : in String;
  1666.       Set  : in Type_Set)
  1667.    is
  1668.       Length : Integer := Item'Length;
  1669.       C      : Character;
  1670.  
  1671.    begin
  1672.       if Length > To'Length then
  1673.          raise Layout_Error;
  1674.       else
  1675.          for J in 0 .. Length - 1 loop
  1676.             C := Item (Item'First + J);
  1677.  
  1678.             --  This is wrong, must use proper casing stuff in strings
  1679.             --  packages ???
  1680.  
  1681.             if Set = Lower_Case and then C in 'A' .. 'Z' then
  1682.                To (To'First + J) := Character'Val (Character'Pos (C) + 32);
  1683.             else
  1684.                To (To'First + J) := C;
  1685.             end if;
  1686.          end loop;
  1687.  
  1688.          for J in Length .. To'Length - 1 loop
  1689.             To (To'First + J) := ' ';
  1690.          end loop;
  1691.       end if;
  1692.    end Put_Enum;
  1693.  
  1694.    --------------
  1695.    -- Put_Page --
  1696.    --------------
  1697.  
  1698.    procedure Put_Page is
  1699.    begin
  1700.       Fputc (The_File.Desc, Page_Mark);
  1701.       The_File.Page := The_File.Page + 1;
  1702.       The_File.Line := 1;
  1703.       The_File.Col := 1;
  1704.    end Put_Page;
  1705.  
  1706.    ---------------
  1707.    -- Put_Line1 --
  1708.    ---------------
  1709.  
  1710.    procedure Put_Line1 is
  1711.    begin
  1712.       Fputc (The_File.Desc, Line_Feed);
  1713.       The_File.Col := 1;
  1714.  
  1715.       if The_File.Page_Length > 0
  1716.          and The_File.Line >= The_File.Page_Length
  1717.       then
  1718.          Put_Page;
  1719.       else
  1720.          The_File.Line := The_File.Line + 1;
  1721.       end if;
  1722.    end Put_Line1;
  1723.  
  1724.    ---------------------
  1725.    -- Check_Opened_Ok --
  1726.    ---------------------
  1727.  
  1728.    procedure Check_Opened_Ok is
  1729.    begin
  1730.       if The_File.Desc = File_Ptr (Null_Address) then
  1731.          raise Name_Error; --  Error opening file due to invalid name
  1732.       end if;
  1733.    end Check_Opened_Ok;
  1734.  
  1735.    ---------------------
  1736.    -- Check_File_Open --
  1737.    ---------------------
  1738.  
  1739.    procedure Check_File_Open is
  1740.    begin
  1741.       --  There are two ways a file can appear closed. Either it is null
  1742.       --  which indicates that it was not used as an argument of an Open_Create
  1743.       --  call or it is not null but its Is_Open field is False which indicates
  1744.       --  that the file was used in an Open/Create but subsequently was closed.
  1745.  
  1746.       if The_File = null then
  1747.          raise Status_Error; --  File not open
  1748.       end if;
  1749.    end Check_File_Open;
  1750.  
  1751.    ---------------------------
  1752.    -- Check_Status_And_Mode --
  1753.    ---------------------------
  1754.  
  1755.    procedure Check_Status_And_Mode (C_Mode : File_Mode) is
  1756.    begin
  1757.       Check_File_Open;
  1758.  
  1759.       if The_File.Mode /= C_Mode then
  1760.          raise Mode_Error;
  1761.       end if;
  1762.    end Check_Status_And_Mode;
  1763.  
  1764.    ---------------------------
  1765.    -- Check_Status_And_Mode --
  1766.    ---------------------------
  1767.  
  1768.    procedure Check_Status_And_Mode (C_Mode1, C_Mode2 : File_Mode) is
  1769.    begin
  1770.       Check_File_Open;
  1771.  
  1772.       if The_File.Mode /= C_Mode1 and then The_File.Mode /= C_Mode2 then
  1773.          raise Mode_Error;
  1774.       end if;
  1775.    end Check_Status_And_Mode;
  1776.  
  1777.    -------------------
  1778.    -- Allocate_AFCB --
  1779.    --------------------
  1780.  
  1781.    procedure Allocate_AFCB is
  1782.       File_Num : Integer := Open_Files'First;
  1783.  
  1784.    begin
  1785.       --  Loop through the array of AFCBs stopping at the first vacate spot
  1786.       --  that is not currently being used.
  1787.  
  1788.       while File_Num <= Max_Num_Of_Files
  1789.         and then Open_Files (File_Num) /= null
  1790.         and then Open_Files (File_Num).AFCB_In_Use
  1791.       loop
  1792.          File_Num := File_Num + 1;
  1793.       end loop;
  1794.  
  1795.       --  No vacant spots were available since too many file are open
  1796.  
  1797.       if File_Num > Max_Num_Of_Files then
  1798.          raise Use_Error;  --  Too many files open
  1799.       end if;
  1800.  
  1801.       if Open_Files (File_Num) = null then
  1802.          Open_Files (File_Num) := new AFCB;
  1803.       end if;
  1804.  
  1805.       The_File := Open_Files (File_Num);
  1806.    end Allocate_AFCB;
  1807.  
  1808.    -------------------------
  1809.    -- Make_Temp_File_Name --
  1810.    -------------------------
  1811.  
  1812.    procedure Make_Temp_File_Name is
  1813.       Temp_File_Name  : String (1 .. 14);
  1814.       --  The template for temporary file name creation using Mktemp.
  1815.  
  1816.       procedure mktemp (S : Address);
  1817.       pragma Import (C, mktemp);
  1818.       --  mktemp creates a unique temporary file name given the address of
  1819.       --  a null terminated template.
  1820.  
  1821.    begin
  1822.       --  Create a template string which the call to mktemp will fill in to
  1823.       --  generate unique name file name.
  1824.  
  1825.       Temp_File_Name (1 .. 13) := "ADATEMPXXXXXX";
  1826.       Temp_File_Name (14) := Ascii.Nul;
  1827.       mktemp (Temp_File_Name'Address);
  1828.       The_File.Name := new String'(Temp_File_Name (1 .. 13));
  1829.  
  1830.       --  Append the name of the temporary file to the beginning of the
  1831.       --  Temp_File list which will be used for deleting all the temporary
  1832.       --  files after completion of the main program.
  1833.  
  1834.       Temp_Files := new Temp_File_Rec'(The_File.Name, Temp_Files);
  1835.    end Make_Temp_File_Name;
  1836.  
  1837.    -------------------------------
  1838.    -- Check_Multiple_File_Opens --
  1839.    -------------------------------
  1840.  
  1841.    procedure Check_Multiple_File_Opens is
  1842.    begin
  1843.       --  Allow a several opens to read an external file, but not one open to
  1844.       --  read and another open to write a external file.
  1845.  
  1846.       for J in Open_Files'Range loop
  1847.          if Open_Files (J) /= null and then Open_Files (J).AFCB_In_Use then
  1848.             if The_File.Name.all = Open_Files (J).Name.all
  1849.               and then (The_File.Mode /= In_File
  1850.                          or else Open_Files (J).Mode /= In_File)
  1851.             then
  1852.                raise Use_Error; --  File already open
  1853.             end if;
  1854.          end if;
  1855.       end loop;
  1856.    end Check_Multiple_File_Opens;
  1857.  
  1858.    -----------------------------
  1859.    --  Page_Is_Not_Terminated --
  1860.    -----------------------------
  1861.  
  1862.    function Page_Is_Not_Terminated return Boolean is
  1863.    begin
  1864.       return not (The_File.Col = 1
  1865.         and then The_File.Line = 1
  1866.         and then The_File.Page /= 1);
  1867.    end Page_Is_Not_Terminated;
  1868.  
  1869.    ----------------
  1870.    -- Close_File --
  1871.    ----------------
  1872.  
  1873.    procedure Close_File is
  1874.       procedure Fclose (F : Text_IO.File_Ptr);
  1875.       pragma Import (C, fclose);
  1876.  
  1877.       File_Num : Integer := Open_Files'First;
  1878.  
  1879.    begin
  1880.       while File_Num <= Max_Num_Of_Files
  1881.          and then Open_Files (File_Num) /= The_File
  1882.       loop
  1883.          File_Num := File_Num + 1;
  1884.       end loop;
  1885.  
  1886.       if File_Num > Max_Num_Of_Files then
  1887.          raise Status_Error;
  1888.       end if;
  1889.  
  1890.       Fclose (The_File.Desc);
  1891.       The_File.AFCB_In_Use := False;
  1892.  
  1893.    end Close_File;
  1894.  
  1895.    ---------------------
  1896.    -- Load_Look_Ahead --
  1897.    ---------------------
  1898.  
  1899.    procedure Load_Look_Ahead (End_Of_File_Flag : Boolean) is
  1900.       C      : Character;
  1901.       Is_Eof : Boolean;
  1902.  
  1903.    begin
  1904.       --  Load first character of look ahead
  1905.  
  1906.       if Chars = 0 then
  1907.          Set_Char2 (Nul);
  1908.          Set_Char3 (Nul);
  1909.          C_Fgetc (The_File.Desc, C, Is_Eof);
  1910.  
  1911.          if Is_Eof then
  1912.             Set_Char1 (Nul);
  1913.             return;
  1914.          else
  1915.             Set_Char1 (C);
  1916.             Set_Chars (1);
  1917.          end if;
  1918.       end if;
  1919.  
  1920.       --  In the case where reading from the keyboard do not read more than
  1921.       --  1 character unless you are processing an end_of_file test.
  1922.  
  1923.       if Is_Keyboard (The_File) and then not End_Of_File_Flag then
  1924.          return;
  1925.       end if;
  1926.  
  1927.       --  Load second character of look ahead
  1928.  
  1929.       if Chars = 1 then
  1930.          Set_Char3 (Nul);
  1931.          C_Fgetc (The_File.Desc, C, Is_Eof);
  1932.  
  1933.          if Is_Eof then
  1934.             Set_Char2 (Nul);
  1935.             return;
  1936.          else
  1937.             Set_Char2 (C);
  1938.             Set_Chars (2);
  1939.          end if;
  1940.       end if;
  1941.  
  1942.       --  Leave lookahead with at most two characters loaded if standard
  1943.       --  input is the keyboard.
  1944.  
  1945.       if not Is_Keyboard (The_File) then
  1946.  
  1947.          --  Load third character of look ahead
  1948.  
  1949.          if Chars = 2 then
  1950.             C_Fgetc (The_File.Desc, C, Is_Eof);
  1951.  
  1952.             if Is_Eof then
  1953.                Set_Char3 (Nul);
  1954.                return;
  1955.             else
  1956.                Set_Char3 (C);
  1957.                Set_Chars (3);
  1958.             end if;
  1959.          end if;
  1960.       end if;
  1961.    end Load_Look_Ahead;
  1962.  
  1963.    --------------
  1964.    -- Get_Char --
  1965.    --------------
  1966.  
  1967.    function Get_Char return Character is
  1968.       C : Character;
  1969.  
  1970.    begin
  1971.       Load_Look_Ahead (False);
  1972.  
  1973.       if Chars = 0 then
  1974.          raise End_Error;  --  End of file on TEXT_IO input
  1975.       end if;
  1976.  
  1977.       C := Char1;
  1978.  
  1979.       --  Update lookahead
  1980.  
  1981.       Set_Char1 (Char2);
  1982.       Set_Char2 (Char3);
  1983.       Set_Char3 (Nul);
  1984.       Set_Chars (Chars - 1);
  1985.  
  1986.       --  Update PAGE and LINE counters if page mark or line feed read
  1987.  
  1988.       if C = Page_Mark then
  1989.          The_File.Page := The_File.Page + 1;
  1990.          The_File.Line := 1;
  1991.          The_File.Col := 1;
  1992.       elsif C = Line_Feed then
  1993.          The_File.Line := The_File.Line + 1;
  1994.          The_File.Col := 1;
  1995.       else
  1996.          The_File.Col := The_File.Col  + 1;
  1997.       end if;
  1998.  
  1999.       return C;
  2000.    end Get_Char;
  2001.  
  2002.    ----------------
  2003.    -- Upper_Case --
  2004.    ----------------
  2005.  
  2006.    function Upper_Case (C : Character) return Character is
  2007.       V : constant Integer := 32;
  2008.  
  2009.    begin
  2010.       if C in 'a' .. 'z' then
  2011.          return Character'Val (Character'Pos (C) - V);
  2012.       else
  2013.          return C;
  2014.       end if;
  2015.    end Upper_Case;
  2016.  
  2017.    --------------
  2018.    -- Word_Sub --
  2019.    --------------
  2020.  
  2021.    procedure Word_Sub
  2022.      (A : Integer;
  2023.       B : Integer;
  2024.       O : out Boolean;
  2025.       R : out Integer)
  2026.    is
  2027.    begin
  2028.       R := A - B;
  2029.       O := ((A < 0 and then B > 0) or else (A > 0 and then B < 0))
  2030.            and then ((A < 0 and then R > 0) or else (A > 0 and then R < 0));
  2031.    end Word_Sub;
  2032.  
  2033.    --------------
  2034.    -- Word_Mul --
  2035.    --------------
  2036.  
  2037.    procedure Word_Mul
  2038.      (A : Integer;
  2039.       B : Integer;
  2040.       O : out Boolean;
  2041.       R : out Integer)
  2042.    is
  2043.    begin
  2044.       if A /= 0 then
  2045.          R := A * B;
  2046.          O := (B /= R / A) or else (A = -1 and then B < 0 and then R < 0);
  2047.       else
  2048.          R := 0;
  2049.          O := False;
  2050.       end if;
  2051.    end Word_Mul;
  2052.  
  2053.    ----------------
  2054.    -- Put_Blanks --
  2055.    ----------------
  2056.  
  2057.    procedure Put_Blanks (N : Integer) is
  2058.    begin
  2059.       for J in 1 .. N loop
  2060.          Fputc (The_File.Desc, ' ');
  2061.       end loop;
  2062.    end Put_Blanks;
  2063.  
  2064.    ----------------
  2065.    -- Put_Buffer --
  2066.    ----------------
  2067.  
  2068.    procedure Put_Buffer
  2069.      (Width    : Integer;
  2070.       Pad_Type : Character;
  2071.       Length   : Integer)
  2072.    is
  2073.       Pad           : Character := Pad_Type;
  2074.       Target_Length : Integer;
  2075.  
  2076.    begin
  2077.       if Length >= Width then
  2078.          Target_Length := Length;
  2079.          Pad := ' ';
  2080.       else
  2081.          Target_Length := Width;
  2082.       end if;
  2083.  
  2084.       --  Ensure the buffer size does not exceed the line length
  2085.  
  2086.       if The_File.Line_Length > 0 then
  2087.          if Count (Target_Length) > The_File.Line_Length then
  2088.             raise Layout_Error; --  "Line too big"
  2089.  
  2090.          --  New line if does not fit on current line
  2091.  
  2092.          elsif The_File.Col +
  2093.            Count (Target_Length) - 1 > The_File.Line_Length
  2094.          then
  2095.             Put_Line1;
  2096.          end if;
  2097.       end if;
  2098.  
  2099.       --  Output data with the required padding
  2100.  
  2101.       if Pad = 'L' then
  2102.          Put_Blanks (Width - Length);
  2103.       end if;
  2104.  
  2105.       for N in 0 .. Length - 1 loop
  2106.          Fputc (The_File.Desc, Work_String (N));
  2107.       end loop;
  2108.  
  2109.       The_File.Col := The_File.Col + Count (Target_Length);
  2110.  
  2111.       if Pad = 'T' then
  2112.          Put_Blanks (Width - Length);
  2113.       end if;
  2114.    end Put_Buffer;
  2115.  
  2116.    -----------
  2117.    -- Getcp --
  2118.    -----------
  2119.  
  2120.    function Getcp return Character is
  2121.       C : Character;
  2122.  
  2123.    begin
  2124.       if Scanning_From_File then
  2125.          return Get_Char;
  2126.       else
  2127.          if WS_Index1 > WS_Length then
  2128.             raise End_Error;
  2129.          end if;
  2130.  
  2131.          WS_Index1 := WS_Index1 + 1;
  2132.          return Work_String (WS_Index1);
  2133.       end if;
  2134.    end Getcp;
  2135.  
  2136.    -----------
  2137.    -- Nextc --
  2138.    -----------
  2139.  
  2140.    function Nextc return Character is
  2141.    begin
  2142.       if Scanning_From_File then
  2143.          Load_Look_Ahead (False);
  2144.          return Char1;
  2145.       else
  2146.          if WS_Index1 < WS_Length then
  2147.             return Work_String (WS_Index1);
  2148.          else
  2149.             return Line_Feed;
  2150.          end if;
  2151.       end if;
  2152.    end Nextc;
  2153.  
  2154.    -----------
  2155.    -- Skipc --
  2156.    -----------
  2157.  
  2158.    procedure Skipc is
  2159.       C : Character;
  2160.  
  2161.    begin
  2162.       if Scanning_From_File then
  2163.          C := Get_Char;
  2164.       else
  2165.          WS_Index1 := WS_Index1 + 1;
  2166.       end if;
  2167.    end Skipc;
  2168.  
  2169.    -----------
  2170.    -- Copyc --
  2171.    -----------
  2172.  
  2173.    procedure Copyc is
  2174.       C : Character;
  2175.  
  2176.    begin
  2177.       if Scanning_From_File then
  2178.          C := Get_Char;
  2179.       else
  2180.          if WS_Index1 > WS_Length then
  2181.             raise Program_Error;
  2182.          else
  2183.             C := Work_String (WS_Index1);
  2184.             WS_Index1 := WS_Index1 + 1;
  2185.          end if;
  2186.       end if;
  2187.  
  2188.       Work_String (WS_Index2) := Upper_Case (C);
  2189.       WS_Index2 := WS_Index2 + 1;
  2190.    end Copyc;
  2191.  
  2192.    ------------------
  2193.    -- Copy_Integer --
  2194.    ------------------
  2195.  
  2196.    procedure Copy_Integer is
  2197.    begin
  2198.       Check_Digit;
  2199.       while Digit (Nextc) loop
  2200.          Copyc;
  2201.  
  2202.          if Nextc = '_' then
  2203.             Skipc;
  2204.             Check_Digit;
  2205.          end if;
  2206.       end loop;
  2207.    end Copy_Integer;
  2208.  
  2209.    ------------------------
  2210.    -- Copy_Based_Integer --
  2211.    ------------------------
  2212.  
  2213.    procedure Copy_Based_Integer is
  2214.    begin
  2215.       Check_Extended_Digit;
  2216.  
  2217.       while Extended_Digit (Nextc) loop
  2218.          Copyc;
  2219.  
  2220.          if Nextc = '_' then
  2221.             Skipc;
  2222.             Check_Extended_Digit;
  2223.          end if;
  2224.       end loop;
  2225.    end Copy_Based_Integer;
  2226.  
  2227.    -----------------
  2228.    -- Scan_Blanks --
  2229.    -----------------
  2230.  
  2231.    procedure Scan_Blanks is
  2232.       C : Character;
  2233.    begin
  2234.       if Scanning_From_File then
  2235.          loop
  2236.             Load_Look_Ahead (False);
  2237.  
  2238.             if Chars = 0 then
  2239.                raise End_Error;
  2240.             end if;
  2241.  
  2242.             C := Nextc;
  2243.  
  2244.             if C = ' '
  2245.               or else C = Ascii.HT
  2246.               or else C = Line_Feed
  2247.               or else C = Page_Mark
  2248.             then
  2249.                C := Getcp;
  2250.             else
  2251.                exit;
  2252.             end if;
  2253.          end loop;
  2254.  
  2255.       else
  2256.          while WS_Index1 <= WS_Length - 1 loop
  2257.             if Work_String (WS_Index1) = ' '
  2258.               or else Work_String (WS_Index1) = Ascii.HT
  2259.             then
  2260.                WS_Index1 := WS_Index1 + 1;
  2261.             else
  2262.                exit;
  2263.             end if;
  2264.          end loop;
  2265.       end if;
  2266.    end Scan_Blanks;
  2267.  
  2268.    ------------------------
  2269.    -- Setup_Fixed_Field --
  2270.    ------------------------
  2271.  
  2272.    procedure Setup_Fixed_Field (Width : Integer) is
  2273.       J : Integer := 0;
  2274.  
  2275.    begin
  2276.       loop
  2277.          Load_Look_Ahead (False);
  2278.  
  2279.          if Width /= J
  2280.            and then Chars /= 0
  2281.            and then Char1 /= Page_Mark
  2282.            and then Char1 /= Line_Feed
  2283.          then
  2284.             Work_String (J) := Get_Char;
  2285.             J := J + 1;
  2286.          else
  2287.             exit;
  2288.          end if;
  2289.       end loop;
  2290.  
  2291.       WS_Length := J;
  2292.       Scanning_From_File := False;
  2293.       WS_Index1 := 0;
  2294.    end Setup_Fixed_Field;
  2295.  
  2296.    --------------------------
  2297.    -- Test_Fixed_Field_End --
  2298.    --------------------------
  2299.  
  2300.    procedure Test_Fixed_Field_End is
  2301.    begin
  2302.       Scan_Blanks;
  2303.  
  2304.       if WS_Index1 < WS_Length then
  2305.          raise Data_Error;
  2306.       end if;
  2307.    end Test_Fixed_Field_End;
  2308.  
  2309.    -----------
  2310.    -- Alpha --
  2311.    -----------
  2312.  
  2313.    function Alpha (C : Character) return Boolean is
  2314.    begin
  2315.       return C in 'A' .. 'Z' or else C in 'a' .. 'z';
  2316.    end Alpha;
  2317.  
  2318.    --------------
  2319.    -- Alphanum --
  2320.    --------------
  2321.  
  2322.    function Alphanum (C : Character) return Boolean is
  2323.    begin
  2324.       return Alpha (C) or else C in '0' .. '9';
  2325.    end Alphanum;
  2326.  
  2327.    -------------
  2328.    -- Graphic --
  2329.    -------------
  2330.  
  2331.    function Graphic (C : Character) return Boolean is
  2332.    begin
  2333.       return Character'Pos (C) in 16#20# .. 16#7E#
  2334.         or else Character'Pos (C) in 16#A0# .. 16#FF#;
  2335.    end Graphic;
  2336.  
  2337.    -----------
  2338.    -- Digit --
  2339.    -----------
  2340.  
  2341.    function Digit (C : Character) return Boolean is
  2342.    begin
  2343.       return C in '0' .. '9';
  2344.    end Digit;
  2345.  
  2346.    --------------------
  2347.    -- Extended_Digit --
  2348.    --------------------
  2349.  
  2350.    function Extended_Digit (C : Character) return Boolean is
  2351.    begin
  2352.       return C in '0' .. '9' or else C in 'a' .. 'f' or else C in 'A' .. 'F';
  2353.    end Extended_Digit;
  2354.  
  2355.    ----------
  2356.    -- Sign --
  2357.    ----------
  2358.  
  2359.    function Sign (C : Character) return Boolean is
  2360.    begin
  2361.       return C = '-' or C = '+';
  2362.    end Sign;
  2363.  
  2364.    -----------------
  2365.    -- Check_Digit --
  2366.    -----------------
  2367.  
  2368.    procedure Check_Digit is
  2369.    begin
  2370.       if not (Nextc in '0' .. '9') then
  2371.          raise Data_Error;
  2372.       end if;
  2373.    end Check_Digit;
  2374.  
  2375.    ----------------
  2376.    -- Check_Hash --
  2377.    ----------------
  2378.  
  2379.    procedure Check_Hash (C : Character) is
  2380.    begin
  2381.       if Nextc /= C then
  2382.          raise Data_Error;
  2383.       end if;
  2384.  
  2385.       Skipc;
  2386.       Work_String (WS_Index2) := '#';
  2387.       WS_Index2 := WS_Index2 + 1;
  2388.    end Check_Hash;
  2389.  
  2390.    --------------------------
  2391.    -- Check_Extended_Digit --
  2392.    --------------------------
  2393.  
  2394.    procedure Check_Extended_Digit is
  2395.    begin
  2396.       if not Extended_Digit (Nextc) then
  2397.          raise Data_Error;
  2398.       end if;
  2399.    end Check_Extended_Digit;
  2400.  
  2401.    -----------------
  2402.    -- Range_Error --
  2403.    -----------------
  2404.  
  2405.    procedure Range_Error is
  2406.    begin
  2407.       raise Data_Error;
  2408.    end Range_Error;
  2409.  
  2410.    --------------
  2411.    -- Scan_Int --
  2412.    --------------
  2413.  
  2414.    function Scan_Int return Integer is
  2415.       Ival        : Integer := 0;
  2416.       Digit_Value : Integer;
  2417.       Overflow1   : Boolean;
  2418.       Overflow2   : Boolean;
  2419.  
  2420.    begin
  2421.       while WS_Index2 < WS_Length
  2422.         and then Digit (Work_String (WS_Index2))
  2423.       loop
  2424.          Digit_Value := Character'Pos (Work_String (WS_Index2))
  2425.                         - Character'Pos ('0');
  2426.          WS_Index2 := WS_Index2 + 1;
  2427.          Word_Mul (Ival, 10, Overflow1, Ival);
  2428.          Word_Sub (Ival, Digit_Value, Overflow2, Ival);
  2429.  
  2430.          if Overflow1 or else Overflow2 then
  2431.             while WS_Index2 < WS_Length
  2432.               and then Digit (Work_String (WS_Index2))
  2433.             loop
  2434.                WS_Index2 := WS_Index2 + 1;
  2435.             end loop;
  2436.             return 1;
  2437.          end if;
  2438.       end loop;
  2439.  
  2440.       return Ival;
  2441.    end Scan_Int;
  2442.  
  2443.    --------------------
  2444.    -- Scan_Based_Int --
  2445.    --------------------
  2446.  
  2447.    --  This routine scans a based Integer value fromt the string pointed by
  2448.    --  the global Integer WS_Index2. On exit WS_Index2 is updated to point
  2449.    --  to the first non-digit. The result returned is always negative. This
  2450.    --  allows the largest negative Integer value to be properly stored and
  2451.    --  converted. If overflow is detected, then the value +1 is returned to
  2452.    --  signal overflow.
  2453.  
  2454.    function Scan_Based_Int (Base : Integer) return Integer is
  2455.       Ival        : Integer := 0;
  2456.       Digit_Value : Integer;
  2457.       Overflow1   : Boolean;
  2458.       Overflow2   : Boolean;
  2459.  
  2460.    begin
  2461.       while WS_Index2 < WS_Length
  2462.         and then Extended_Digit (Work_String (WS_Index2))
  2463.       loop
  2464.          Word_Mul (Ival, Base, Overflow1, Ival);
  2465.          Digit_Value := Character'Pos (Work_String (WS_Index2))
  2466.                                        - Character'Pos ('0');
  2467.          WS_Index2 := WS_Index2 + 1;
  2468.  
  2469.          if Digit_Value > 9 then
  2470.             Digit_Value := Digit_Value - 7;
  2471.          end if;
  2472.  
  2473.          if Digit_Value >= Base then
  2474.             raise Data_Error;
  2475.          end if;
  2476.  
  2477.          Word_Sub (Ival, Digit_Value, Overflow2, Ival);
  2478.  
  2479.          if Overflow1 or else Overflow2 then
  2480.             while WS_Index2 < WS_Length
  2481.               and then Extended_Digit (Work_String (WS_Index2))
  2482.             loop
  2483.                WS_Index2 := WS_Index2 + 1;
  2484.             end loop;
  2485.             return 1;
  2486.          end if;
  2487.       end loop;
  2488.  
  2489.       return Ival;
  2490.    end Scan_Based_Int;
  2491.  
  2492.    ----------------------
  2493.    -- Scan_Integer_Val --
  2494.    ----------------------
  2495.  
  2496.    procedure Scan_Integer_Val (Fixed_Field : Boolean; Result : out Integer) is
  2497.       Ival     : Integer;
  2498.       Sign_Val : Character;
  2499.       C        : Character;
  2500.       Base     : Integer;
  2501.       Based    : Boolean;
  2502.       Exponent : Integer;
  2503.       Overflow : Boolean;
  2504.  
  2505.    begin
  2506.       --  First scan out item with the proper syntax and put it in Work_String
  2507.  
  2508.       WS_Index2 := 0;
  2509.  
  2510.       if Sign (Nextc) then
  2511.          Copyc;
  2512.       end if;
  2513.  
  2514.       Copy_Integer;
  2515.       C := Nextc;
  2516.  
  2517.       if C = '#' or else C = ':' then
  2518.          Skipc;
  2519.          Work_String (WS_Index2) := '#';
  2520.          WS_Index2 := WS_Index2 + 1;
  2521.          Copy_Based_Integer;
  2522.          Check_Hash (C);
  2523.          Based := True;
  2524.       else
  2525.          Based := False;
  2526.       end if;
  2527.  
  2528.       C := Nextc;
  2529.  
  2530.       if C = 'e' or else C = 'E' then
  2531.          Copyc;
  2532.          C := Nextc;
  2533.  
  2534.          if C = '+' or else C = '-' then
  2535.             Skipc;
  2536.          end if;
  2537.  
  2538.          Copy_Integer;
  2539.  
  2540.          if C = '-' then
  2541.             raise Data_Error;  --  Negative exponent in integer value
  2542.          end if;
  2543.       end if;
  2544.  
  2545.       if Fixed_Field then
  2546.          Test_Fixed_Field_End;
  2547.       end if;
  2548.  
  2549.       WS_Length := WS_Index2;
  2550.       Work_String (WS_Index2) := ' ';
  2551.  
  2552.       --  Now we have the Integer literal stored in Work_String
  2553.  
  2554.       WS_Index2 := 0;
  2555.  
  2556.       if Sign (Work_String (WS_Index2)) then
  2557.          Sign_Val := Work_String (WS_Index2);
  2558.          WS_Index2 := WS_Index2 + 1;
  2559.       else
  2560.          Sign_Val := '+';
  2561.       end if;
  2562.  
  2563.       if Based then
  2564.          Base := -Scan_Int;
  2565.  
  2566.          if not (Base in 2 .. 16) then
  2567.             raise Data_Error;
  2568.          end if;
  2569.  
  2570.          WS_Index2 := WS_Index2 + 1;
  2571.          Ival := Scan_Based_Int (Base);
  2572.          WS_Index2 := WS_Index2 + 1;
  2573.  
  2574.       else
  2575.          Ival := Scan_Int;
  2576.          Base := 10;
  2577.       end if;
  2578.  
  2579.       --  Number is in Ival (in negative form), deal with exponent.
  2580.  
  2581.       if Ival = 1 then
  2582.          Range_Error;
  2583.       end if;
  2584.  
  2585.       if Work_String (WS_Index2) = 'E' then
  2586.          WS_Index2 := WS_Index2 + 1;
  2587.          Exponent := Scan_Int;
  2588.  
  2589.          if Exponent < -64 or else Exponent = 1 then
  2590.             Range_Error;
  2591.          end if;
  2592.  
  2593.          while Exponent /= 0 loop
  2594.             Exponent := Exponent + 1;
  2595.             Word_Mul (Ival, Base, Overflow, Ival);
  2596.  
  2597.             if Overflow then
  2598.                Range_Error;
  2599.             end if;
  2600.          end loop;
  2601.       else
  2602.          WS_Index2 := WS_Index2 + 1;
  2603.       end if;
  2604.  
  2605.       if Sign_Val = '+' then
  2606.          Ival := -Ival;
  2607.  
  2608.          if Ival < 0 then
  2609.             Range_Error;
  2610.          end if;
  2611.       end if;
  2612.  
  2613.       Result := Ival;
  2614.    end Scan_Integer_Val;
  2615.  
  2616.    ------------------
  2617.    -- Scan_Integer --
  2618.    ------------------
  2619.  
  2620.    procedure Scan_Integer (Width : Integer; Result : out Integer) is
  2621.    begin
  2622.       if Width /= 0 then
  2623.          Setup_Fixed_Field (Width);
  2624.          Scan_Blanks;
  2625.  
  2626.          if WS_Index1 = WS_Length then
  2627.             raise Data_Error;  --  String is all blanks
  2628.          end if;
  2629.  
  2630.          Scan_Integer_Val (True, Result);
  2631.       else
  2632.          Scanning_From_File := True;
  2633.          Scan_Blanks;
  2634.          Scan_Integer_Val (False, Result);
  2635.       end if;
  2636.    end Scan_Integer;
  2637.  
  2638.    --------------------
  2639.    -- Scan_Real_Val --
  2640.    --------------------
  2641.  
  2642.    --  Procedure to scan a real value and return the result as a double real.
  2643.    --  A range exception is signalled if the value is out of range of allowed
  2644.    --  Ada real values, but no other range check is made.
  2645.  
  2646.    function Scan_Real_Val (Fixed_Field : Boolean) return LLF is
  2647.       Base         : Integer;        --  base as integer
  2648.       Based        : Boolean;        --  True if number is based
  2649.       Before_Point : Boolean;        --  True if before decimal point
  2650.       C            : Character;      --  character scanned
  2651.       Dbase        : LLF;            --  base as real
  2652.       Dig          : Integer;        --  next digit value
  2653.       Ddig         : LLF;            --  next digit as real
  2654.       Dval         : LLF;            --  value being scanned
  2655.       Exp_Sign_Val : Character;      --  sign of exponent
  2656.       Fraction     : LLF;            --  power of ten fraction after decimal pt
  2657.       Sign_Val     : Character;      --  sign of mantissa
  2658.       Exponent     : Integer;        --  value of exponent
  2659.  
  2660.    begin
  2661.       --  First scan out item with the proper syntax and put it in work_string
  2662.  
  2663.       WS_Index2 := 0;
  2664.  
  2665.       if Sign (Nextc) then
  2666.          Copyc;
  2667.       end if;
  2668.  
  2669.       Copy_Integer;
  2670.       C := Nextc;
  2671.  
  2672.       if C = '#' or else C = ':' then
  2673.          Skipc;
  2674.          Work_String (WS_Index2) := '#';
  2675.          WS_Index2 := WS_Index2 + 1;
  2676.          Copy_Based_Integer;
  2677.  
  2678.          if Nextc /= '.' then
  2679.             raise Data_Error; --  missing period in real value
  2680.          end if;
  2681.  
  2682.          Copyc;
  2683.          Copy_Based_Integer;
  2684.          Check_Hash (C);
  2685.          Based := True;
  2686.  
  2687.       else
  2688.          Based := False;
  2689.  
  2690.          if Nextc /= '.' then
  2691.             raise Data_Error; --  Missing period in real value
  2692.          end if;
  2693.  
  2694.          Copyc;
  2695.          Copy_Integer;
  2696.       end if;
  2697.  
  2698.       C := Nextc;
  2699.  
  2700.       if C = 'e' or else C = 'E' then
  2701.          Copyc;
  2702.          C := Nextc;
  2703.  
  2704.          if Sign (Nextc) then
  2705.             Copyc;
  2706.          end if;
  2707.  
  2708.          Copy_Integer;
  2709.       end if;
  2710.  
  2711.       if Fixed_Field then
  2712.          Test_Fixed_Field_End;
  2713.       end if;
  2714.  
  2715.       WS_Length := WS_Index2;
  2716.  
  2717.       --  Now we have the real literal stored in work_string, so prepare to
  2718.       --  convert the value, dealing first with setting the proper sign. Note
  2719.       --  that we can assume that the syntax of the literal is correct since
  2720.       --  we did all the checking above as we scanned it out.
  2721.  
  2722.       WS_Index2 := 0;
  2723.  
  2724.       if Sign (Work_String (WS_Index2)) then
  2725.          Sign_Val := Work_String (WS_Index2);
  2726.          WS_Index2 := WS_Index2 + 1;
  2727.       else
  2728.          Sign_Val := '+';
  2729.       end if;
  2730.  
  2731.       --  Acquire the proper base value. Note that scan_int returns the
  2732.       --  negative of the value scanned, with +1 indicating overflow which
  2733.       --  will be invalid.
  2734.  
  2735.       if Based then
  2736.          Base := Scan_Int;
  2737.  
  2738.          if Base not in -16 .. -2 then
  2739.             raise Data_Error;  --  Invalid base
  2740.          end if;
  2741.  
  2742.          Base := -Base;
  2743.          WS_Index2 := WS_Index2 + 1;
  2744.       else
  2745.          Base := 10;
  2746.       end if;
  2747.  
  2748.       Dbase := LLF (Base);
  2749.  
  2750.       --  Scan and convert digits
  2751.  
  2752.       Dval := 0.0;
  2753.       Before_Point := True;
  2754.  
  2755.       loop
  2756.          exit when WS_Index2 = WS_Length;
  2757.  
  2758.          if Work_String (WS_Index2) = '#' then
  2759.             WS_Index2 := WS_Index2 + 1;
  2760.             exit;
  2761.          end if;
  2762.  
  2763.          exit when (not Based) and then Work_String (WS_Index2) = 'E';
  2764.          C := Work_String (WS_Index2);
  2765.          WS_Index2 := WS_Index2 + 1;
  2766.  
  2767.          if C = '.' then
  2768.             Before_Point := False;
  2769.             Fraction := 1.0;
  2770.          else
  2771.             Dig := Character'Pos (C) - Character'Pos ('0');
  2772.  
  2773.             --  Convert hex digit
  2774.  
  2775.             if Dig > 9 then
  2776.                Dig := Dig - 7;
  2777.             end if;
  2778.  
  2779.             if Dig > Base then
  2780.                raise Data_Error; --  Digit > Base
  2781.             end if;
  2782.  
  2783.             Ddig := LLF (Dig);
  2784.  
  2785.             if Before_Point then
  2786.                Dval := Dval * Dbase + Ddig;
  2787.                --  ???
  2788.                --  if Dval > ADA_MAX_REAL then
  2789.                --     Range_Error;
  2790.                --  end if;
  2791.             else
  2792.                Fraction := Fraction / LLF (Base);
  2793.                Dval := Dval + Ddig * Fraction;
  2794.             end if;
  2795.          end if;
  2796.       end loop;
  2797.  
  2798.       --  Deal with exponent if present
  2799.  
  2800.       if Work_String (WS_Index2) = 'E' then
  2801.          WS_Index2 := WS_Index2 + 1;
  2802.  
  2803.          if Sign (Work_String (WS_Index2)) then
  2804.             Exp_Sign_Val := Work_String (WS_Index2);
  2805.             WS_Index2 := WS_Index2 + 1;
  2806.          else
  2807.             Exp_Sign_Val := '+';
  2808.          end if;
  2809.  
  2810.          Exponent := Scan_Int;
  2811.  
  2812.          --  A value of +1 in exponent means that scan_int detected overflow.
  2813.          --  This is not yet a range error. If the mantissa is 0 or 1, the
  2814.          --  effect is as if we had an exponent of 1.
  2815.  
  2816.          if Exponent = 1 then
  2817.             if Dval = 0.0 or else Dval = 1.0 then
  2818.                Exponent := 1;
  2819.  
  2820.             --  If we have a positive exponent, then if the mantissa is greater
  2821.             --  than 1.0, we do have an overflow, otherwise if the mantissa is
  2822.             --  less than 1.0, we have an underflow situation giving a result
  2823.             --  of zero.
  2824.  
  2825.             elsif Exp_Sign_Val = '+' then
  2826.                if Dval > 1.0 then
  2827.                   Range_Error;
  2828.                else
  2829.                   Dval := 0.0;
  2830.                end if;
  2831.  
  2832.             --  For a negative exponent, the situation is the other way round,
  2833.             --  since we want in effect the reciprocal of the value for the
  2834.             --  positive case.
  2835.  
  2836.             else
  2837.                if Dval > 1.0 then
  2838.                   Dval := 0.0;
  2839.                else
  2840.                   Range_Error;
  2841.                end if;
  2842.             end if;
  2843.  
  2844.          --  If no overflow, get abs value of exponent (scan_int returned -exp)
  2845.  
  2846.          else
  2847.             Exponent := -Exponent;
  2848.          end if;
  2849.  
  2850.          --  An optimization: if the mantissa is zero, save a lot of time
  2851.          --  in converting silly numbers like 0E+25000 by resetting exponent.
  2852.  
  2853.          if Dval = 0.0 then
  2854.             Exponent := 0;
  2855.          end if;
  2856.  
  2857.          --  Adjust mantissa by exponent, using proper exponent sign
  2858.  
  2859.          if Exp_Sign_Val = '+' then
  2860.             while Exponent > 0 loop
  2861.                Dval := Dval * Dbase;
  2862.                --  ???
  2863.                --  if Dval > ADA_MAX_REAL then
  2864.                --     Range_Error;
  2865.                --  end if;
  2866.                Exponent := Exponent - 1;
  2867.             end loop;
  2868.          else
  2869.             while Exponent > 0 loop
  2870.                Dval := Dval / Dbase;
  2871.                Exponent := Exponent - 1;
  2872.             end loop;
  2873.          end if;
  2874.       end if;
  2875.  
  2876.       --  Return scanned value with proper sign
  2877.  
  2878.       if Sign_Val = '+' then
  2879.          return Dval;
  2880.       else
  2881.          return -Dval;
  2882.       end if;
  2883.    end Scan_Real_Val;
  2884.  
  2885.    --------------------
  2886.    -- Scan_Float_Val --
  2887.    --------------------
  2888.  
  2889.    function Scan_Float_Val (Fixed_Field : Boolean) return LLF is
  2890.       Dval : LLF;
  2891.  
  2892.    begin
  2893.       Dval := Scan_Real_Val (Fixed_Field);
  2894.       --  ??? Check that value is in range. Unimplemented for now.
  2895.       return LLF (Dval);
  2896.    end Scan_Float_Val;
  2897.  
  2898.    ----------------
  2899.    -- Scan_Float --
  2900.    ----------------
  2901.  
  2902.    function Scan_Float (Width : Natural) return LLF is
  2903.       Result : LLF;
  2904.  
  2905.    begin
  2906.       if Width /= 0 then
  2907.          Setup_Fixed_Field (Width);
  2908.          Scan_Blanks;
  2909.  
  2910.          if WS_Index1 = WS_Length then
  2911.             raise Data_Error; --  String is all blanks
  2912.          end if;
  2913.  
  2914.          Result := Scan_Float_Val (True);
  2915.       else
  2916.          Scanning_From_File := True;
  2917.          Scan_Blanks;
  2918.          Result := Scan_Float_Val (False);
  2919.       end if;
  2920.  
  2921.       return Result;
  2922.    end Scan_Float;
  2923.  
  2924.    ---------------
  2925.    -- Scan_Enum --
  2926.    ---------------
  2927.  
  2928.    procedure Scan_Enum (Last : out Natural) is
  2929.    begin
  2930.       Scan_Blanks;
  2931.  
  2932.       if not Scanning_From_File and then WS_Index1 = WS_Length then
  2933.          raise End_Error;  --  String is all blanks
  2934.       end if;
  2935.  
  2936.       WS_Index2 := 0;
  2937.  
  2938.       --  Try identifier
  2939.  
  2940.       if Alpha (Nextc) then
  2941.          while Alphanum (Nextc) loop
  2942.             Copyc;
  2943.  
  2944.             if Nextc = '_' then
  2945.                Copyc;
  2946.             end if;
  2947.          end loop;
  2948.  
  2949.       elsif Nextc = ''' then
  2950.  
  2951.       --  Look for an ending quote.
  2952.  
  2953.          Copyc;
  2954.  
  2955.          if Graphic (Nextc) then
  2956.             Work_String (WS_Index2) := Getcp;
  2957.             WS_Index2 := WS_Index2 + 1;
  2958.  
  2959.             if Nextc = ''' then
  2960.                Copyc;
  2961.             end if;
  2962.          else
  2963.             raise Data_Error;
  2964.          end if;
  2965.  
  2966.       else
  2967.          raise Data_Error;
  2968.       end if;
  2969.  
  2970.       WS_Length := WS_Index2;
  2971.       Last := WS_Index1;
  2972.    end Scan_Enum;
  2973.  
  2974.    --  The closing of all open files and deletion of temporary files is an
  2975.    --  action which takes place at the end of execution of the main program.
  2976.    --  This action can be implemented using a library level object which
  2977.    --  gets finalized at the end of the main program execution. Below, a
  2978.    --  controlled type is introduced and an object is declared of this type
  2979.    --  for this purpose. The Finalize operation associated with this type
  2980.    --  will do all the necessary work.
  2981.  
  2982.    type Finalizable_Type is new Controlled with null record;
  2983.    procedure Finalize (V : in out Finalizable_Type);
  2984.  
  2985.    Finalizable_Object : Finalizable_Type;
  2986.  
  2987.    --------------
  2988.    -- Finalize --
  2989.    --------------
  2990.  
  2991.    procedure Finalize (V : in out Finalizable_Type) is
  2992.    begin
  2993.       --  Close all open files except stdin, stdout and stderr
  2994.  
  2995.       for J in 4 .. Open_Files'Last loop
  2996.          if Open_Files (J) /= null
  2997.            and then Open_Files (J).AFCB_In_Use
  2998.            and then Open_Files (J).Mode /= In_File
  2999.          then
  3000.             Close_File;
  3001.          end if;
  3002.       end loop;
  3003.  
  3004.       --  Delete temporary files upon completion of the main program
  3005.  
  3006.       while (Temp_Files /= null) loop
  3007.          Unlink (Temp_Files.File_Name.all);
  3008.          Temp_Files := Temp_Files.Next;
  3009.       end loop;
  3010.    end Finalize;
  3011.  
  3012.    -----------
  3013.    -- Fopen --
  3014.    -----------
  3015.  
  3016.    function Fopen (Name : String; Typ : File_Mode) return Text_IO.File_Ptr is
  3017.       function C_Fopen (Name, Typ : Address) return Text_IO.File_Ptr;
  3018.       pragma Import (C, C_Fopen, "fopen");
  3019.  
  3020.       Name1       : String (Name'First .. Name'Last + 1);
  3021.       Append_Only : constant String := "at" & Ascii.NUL;
  3022.       Read_Only   : constant String := "rt" & Ascii.NUL;
  3023.       Write_Only  : constant String := "wt" & Ascii.NUL;
  3024.  
  3025.    begin
  3026.       Name1 (Name'Range) := Name;
  3027.       Name1 (Name1'Last) := Nul;
  3028.  
  3029.       if Typ = In_File then
  3030.          return C_Fopen (Name1'Address, Read_Only'Address);
  3031.       elsif Typ = Out_File then
  3032.          return C_Fopen (Name1'Address, Write_Only'Address);
  3033.       else  --  Append_File
  3034.          return C_Fopen (Name1'Address, Append_Only'Address);
  3035.       end if;
  3036.    end Fopen;
  3037.  
  3038.    ------------
  3039.    -- Fclose --
  3040.    ------------
  3041.  
  3042.    procedure Fclose (P : Text_IO.File_Ptr) is
  3043.       procedure C_Fclose (P : Text_IO.File_Ptr);
  3044.       pragma Import (C, C_Fclose, "fclose");
  3045.  
  3046.    begin
  3047.       C_Fclose (P);
  3048.    end Fclose;
  3049.  
  3050.    ------------
  3051.    -- Unlink --
  3052.    ------------
  3053.  
  3054.    procedure Unlink (Name : String) is
  3055.       procedure C_Unlink (Name : Address);
  3056.       pragma Import (C, C_Unlink, "unlink");
  3057.  
  3058.       Name1 : String (Name'First .. Name'Last + 1);
  3059.  
  3060.    begin
  3061.       Name1 (Name'Range) := Name;
  3062.       Name1 (Name1'Last) := Nul;
  3063.       C_Unlink (Name1'Address);
  3064.    end Unlink;
  3065.  
  3066.    -----------------
  3067.    -- Is_Keyboard --
  3068.    -----------------
  3069.  
  3070.    function Is_Keyboard (F : Text_IO.File_Type) return Boolean is
  3071.    begin
  3072.       return F.Is_Keyboard;
  3073.    end Is_Keyboard;
  3074.  
  3075.    ------------
  3076.    -- Isatty --
  3077.    ------------
  3078.  
  3079.    function Isatty (F : Text_IO.File_Ptr) return Boolean is
  3080.       function C_Isatty (I : Integer) return Boolean;
  3081.       pragma Import (C, C_Isatty, "isatty");
  3082.  
  3083.       function C_Fileno (F : Text_IO.File_Ptr) return Integer;
  3084.       pragma Import (C, C_Fileno, "fileno");
  3085.  
  3086.    begin
  3087.       return C_Isatty (C_Fileno (F));
  3088.    end Isatty;
  3089.  
  3090.    -------------
  3091.    -- C_Fgetc --
  3092.    -------------
  3093.  
  3094.    procedure C_Fgetc
  3095.      (F      : Text_IO.File_Ptr;
  3096.       C      : out Character;
  3097.       Is_Eof : out Boolean)
  3098.    is
  3099.       I      : Integer;
  3100.       function Fgetc (F : Text_IO.File_Ptr) return Integer;
  3101.       pragma Import (C, Fgetc, "fgetc");
  3102.  
  3103.    begin
  3104.       I := Fgetc (F);
  3105.       Is_Eof := I = -1;
  3106.  
  3107.       if not Is_Eof then
  3108.          C := Character'Val (I);
  3109.       end if;
  3110.    end C_Fgetc;
  3111.  
  3112.    -------------
  3113.    -- C_Fputc --
  3114.    -------------
  3115.  
  3116.    procedure Fputc (F : Text_IO.File_Ptr; C : Character) is
  3117.       procedure C_Fputc (C : Character; F : Text_IO.File_Ptr);
  3118.       pragma Import (C, C_Fputc, "fputc");
  3119.  
  3120.    begin
  3121.       C_Fputc (C, F);
  3122.    end Fputc;
  3123.  
  3124.    -----------
  3125.    -- Stdin --
  3126.    ------------
  3127.  
  3128.    function Stdin return Text_IO.File_Ptr is
  3129.       function C_Stdin return Text_IO.File_Ptr;
  3130.       pragma Import (C, C_Stdin);
  3131.  
  3132.    begin
  3133.       return C_Stdin;
  3134.    end Stdin;
  3135.  
  3136.    ------------
  3137.    -- Stdout --
  3138.    ------------
  3139.  
  3140.    function Stdout return Text_IO.File_Ptr is
  3141.       function C_Stdout return Text_IO.File_Ptr;
  3142.       pragma Import (C, C_Stdout);
  3143.  
  3144.    begin
  3145.       return C_Stdout;
  3146.    end Stdout;
  3147.  
  3148.    ------------
  3149.    -- Stderr --
  3150.    ------------
  3151.  
  3152.    function Stderr return Text_IO.File_Ptr is
  3153.       function C_Stderr return Text_IO.File_Ptr;
  3154.       pragma Import (C, C_Stderr);
  3155.  
  3156.    begin
  3157.       return C_Stderr;
  3158.    end Stderr;
  3159.  
  3160.    -------------------
  3161.    -- Unimplemented --
  3162.    -------------------
  3163.  
  3164.    procedure Unimplemented (Message : String) is
  3165.    begin
  3166.       Text_IO.Put (Message);
  3167.       Text_IO.Put_Line (" not implemented yet");
  3168.    end Unimplemented;
  3169.  
  3170. begin
  3171.    --  Initialization of Standard Input
  3172.  
  3173.    Standard_In := new AFCB'(AFCB_In_Use => True,
  3174.      Desc => Stdin,
  3175.      Name => new String'("Standard_Input"),
  3176.      Form => new String'("rt"),
  3177.      Mode => In_File,
  3178.      Col  => 1,
  3179.      Line => 1,
  3180.      Page => 1,
  3181.      Line_Length => 0,
  3182.      Page_Length => 0,
  3183.      Count => 0,
  3184.      Is_Keyboard => Isatty (Stdin),
  3185.      Look_Ahead => "   ");
  3186.  
  3187.    --  Initialization of Standard Output
  3188.  
  3189.    Standard_Out := new AFCB'(AFCB_In_Use => True,
  3190.      Desc => Stdout,
  3191.      Name => new String'("Standard_Output"),
  3192.      Form => new String'("wt"),
  3193.      Mode => Out_File,
  3194.      Col  => 1,
  3195.      Line => 1,
  3196.      Page => 1,
  3197.      Line_Length => 0,
  3198.      Page_Length => 0,
  3199.      Count => 0,
  3200.      Is_Keyboard => False,
  3201.      Look_Ahead => "   ");
  3202.  
  3203.    --  Initialization of Standard Error
  3204.  
  3205.    Standard_Err := new AFCB'(AFCB_In_Use => True,
  3206.      Desc => Stderr,
  3207.      Name => new String'("Standard_Error"),
  3208.      Form => new String'("wt"),
  3209.      Mode => Out_File,
  3210.      Col  => 1,
  3211.      Line => 1,
  3212.      Page => 1,
  3213.      Line_Length => 0,
  3214.      Page_Length => 0,
  3215.      Count => 0,
  3216.      Is_Keyboard => False,
  3217.      Look_Ahead => "   ");
  3218.  
  3219.    Current_In  := Standard_In;
  3220.    Current_Out := Standard_Out;
  3221.    Current_Err := Standard_Err;
  3222.  
  3223.    Open_Files (Open_Files'First + 0) := Standard_In;
  3224.    Open_Files (Open_Files'First + 1) := Standard_Out;
  3225.    Open_Files (Open_Files'First + 2) := Standard_Err;
  3226.  
  3227. end Ada.Text_IO.Aux;
  3228.